From d0cbe011179695223d49c5aec71849a758c9212a Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Thu, 10 Oct 2024 17:12:25 +0200 Subject: [PATCH 01/17] fix: Container-App-Stack - Trigger publish (#3497) ## Description - Just a small change to ensure the module is published as a previous merge did not do the trick - Also added missing passthru of `enableTelemetry` parameter to this and the insights-dashboard module --- avm/ptn/azd/container-apps-stack/README.md | 4 ++-- avm/ptn/azd/container-apps-stack/main.bicep | 4 +++- avm/ptn/azd/container-apps-stack/main.json | 6 ++--- avm/ptn/azd/insights-dashboard/main.bicep | 6 ++++- avm/ptn/azd/insights-dashboard/main.json | 24 +++++++++++++++---- .../applicationinsights-dashboard.bicep | 4 ++++ 6 files changed, 37 insertions(+), 11 deletions(-) diff --git a/avm/ptn/azd/container-apps-stack/README.md b/avm/ptn/azd/container-apps-stack/README.md index 1702795bd4..a01a8ffb71 100644 --- a/avm/ptn/azd/container-apps-stack/README.md +++ b/avm/ptn/azd/container-apps-stack/README.md @@ -197,7 +197,7 @@ param zoneRedundant = true | :-- | :-- | :-- | | [`dockerBridgeCidr`](#parameter-dockerbridgecidr) | string | CIDR notation IP range assigned to the Docker bridge, network. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant. | | [`infrastructureSubnetResourceId`](#parameter-infrastructuresubnetresourceid) | string | Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if "internal" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant. | -| [`internal`](#parameter-internal) | bool | Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant. | +| [`internal`](#parameter-internal) | bool | Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if 'zoneRedundant' is set to true to make the resource WAF compliant. | | [`platformReservedCidr`](#parameter-platformreservedcidr) | string | IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant. | | [`platformReservedDnsIP`](#parameter-platformreserveddnsip) | string | An IP address from the IP range defined by "platformReservedCidr" that will be reserved for the internal DNS server. It must not be the first address in the range and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant. | | [`workloadProfiles`](#parameter-workloadprofiles) | array | Workload profiles configured for the Managed Environment. Required if zoneRedundant is set to true to make the resource WAF compliant. | @@ -256,7 +256,7 @@ Resource ID of a subnet for infrastructure components. This is used to deploy th ### Parameter: `internal` -Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant. +Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if 'zoneRedundant' is set to true to make the resource WAF compliant. - Required: No - Type: bool diff --git a/avm/ptn/azd/container-apps-stack/main.bicep b/avm/ptn/azd/container-apps-stack/main.bicep index 1319e17f2d..db11a5ed46 100644 --- a/avm/ptn/azd/container-apps-stack/main.bicep +++ b/avm/ptn/azd/container-apps-stack/main.bicep @@ -53,7 +53,7 @@ param dockerBridgeCidr string = '' @description('Conditional. Resource ID of a subnet for infrastructure components. This is used to deploy the environment into a virtual network. Must not overlap with any other provided IP ranges. Required if "internal" is set to true. Required if zoneRedundant is set to true to make the resource WAF compliant.') param infrastructureSubnetResourceId string = '' -@description('Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant.') +@description('Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then "infrastructureSubnetId" must be provided. Required if \'zoneRedundant\' is set to true to make the resource WAF compliant.') param internal bool = false @description('Conditional. IP range in CIDR notation that can be reserved for environment infrastructure IP addresses. It must not overlap with any other provided IP ranges and can only be used when the environment is deployed into a virtual network. If not provided, it will be set with a default value by the platform. Required if zoneRedundant is set to true to make the resource WAF compliant.') @@ -104,6 +104,7 @@ module containerAppsEnvironment 'br/public:avm/res/app/managed-environment:0.7.0 dockerBridgeCidr: dockerBridgeCidr platformReservedCidr: platformReservedCidr platformReservedDnsIP: platformReservedDnsIP + enableTelemetry: enableTelemetry } } @@ -118,6 +119,7 @@ module containerRegistry 'br/public:avm/res/container-registry/registry:0.4.0' = acrAdminUserEnabled: acrAdminUserEnabled tags: tags acrSku: acrSku + enableTelemetry: enableTelemetry } } diff --git a/avm/ptn/azd/container-apps-stack/main.json b/avm/ptn/azd/container-apps-stack/main.json index f58de2af0b..49ae1b6b15 100644 --- a/avm/ptn/azd/container-apps-stack/main.json +++ b/avm/ptn/azd/container-apps-stack/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "332940780345983600" + "version": "0.30.23.60470", + "templateHash": "2135275469617068705" }, "name": "avm/ptn/azd/container-apps-stack", "description": "Creates an Azure Container Registry and an Azure Container Apps environment.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case", @@ -117,7 +117,7 @@ "type": "bool", "defaultValue": false, "metadata": { - "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetId\" must be provided. Required if zoneRedundant is set to true to make the resource WAF compliant." + "description": "Conditional. Boolean indicating the environment only has an internal load balancer. These environments do not have a public static IP resource. If set to true, then \"infrastructureSubnetId\" must be provided. Required if 'zoneRedundant' is set to true to make the resource WAF compliant." } }, "platformReservedCidr": { diff --git a/avm/ptn/azd/insights-dashboard/main.bicep b/avm/ptn/azd/insights-dashboard/main.bicep index 911a2471a7..929b1fd5be 100644 --- a/avm/ptn/azd/insights-dashboard/main.bicep +++ b/avm/ptn/azd/insights-dashboard/main.bicep @@ -72,6 +72,7 @@ module applicationInsights 'br/public:avm/res/insights/component:0.4.1' = { kind: kind applicationType: applicationType workspaceResourceId: logAnalyticsWorkspaceResourceId + enableTelemetry: enableTelemetry } } @@ -82,6 +83,7 @@ module applicationInsightsDashboard 'modules/applicationinsights-dashboard.bicep location: location applicationInsightsName: applicationInsights.outputs.name applicationInsightsResourceId: applicationInsights.outputs.resourceId + enableTelemetry: enableTelemetry } } @@ -102,7 +104,9 @@ output dashboardName string = !empty(dashboardName) ? applicationInsightsDashboa output applicationInsightsResourceId string = applicationInsights.outputs.resourceId @description('The resource ID of the dashboard.') -output dashboardResourceId string = !empty(dashboardName) ? applicationInsightsDashboard.outputs.dashboardResourceId : '' +output dashboardResourceId string = !empty(dashboardName) + ? applicationInsightsDashboard.outputs.dashboardResourceId + : '' @description('The connection string of the application insights.') output applicationInsightsConnectionString string = applicationInsights.outputs.connectionString diff --git a/avm/ptn/azd/insights-dashboard/main.json b/avm/ptn/azd/insights-dashboard/main.json index ed2893f7d0..a082c79e6f 100644 --- a/avm/ptn/azd/insights-dashboard/main.json +++ b/avm/ptn/azd/insights-dashboard/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "16185324363882257699" + "version": "0.30.23.60470", + "templateHash": "15067669928476640283" }, "name": "Application Insights Components", "description": "Creates an Application Insights instance based on an existing Log Analytics workspace.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", @@ -121,6 +121,9 @@ }, "workspaceResourceId": { "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, "template": { @@ -758,6 +761,9 @@ }, "applicationInsightsResourceId": { "value": "[reference('applicationInsights').outputs.resourceId.value]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" } }, "template": { @@ -767,8 +773,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "12382758204242351890" + "version": "0.30.23.60470", + "templateHash": "10844955132300564569" }, "name": "Azure Portal Dashboard", "description": "Creates a dashboard for an Application Insights instance.", @@ -800,6 +806,13 @@ "description": "Optional. Location for all Resources." } }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, "tags": { "type": "object", "nullable": true, @@ -829,6 +842,9 @@ "tags": { "value": "[parameters('tags')]" }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, "lenses": { "value": [ { diff --git a/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep b/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep index 4a08622f49..f358fa0a74 100644 --- a/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep +++ b/avm/ptn/azd/insights-dashboard/modules/applicationinsights-dashboard.bicep @@ -14,6 +14,9 @@ param applicationInsightsResourceId string @description('Optional. Location for all Resources.') param location string = resourceGroup().location +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + @description('Optional. Tags of the resource.') @metadata({ example: ''' @@ -35,6 +38,7 @@ module dashboard 'br/public:avm/res/portal/dashboard:0.1.0' = { name: name location: location tags: tags + enableTelemetry: enableTelemetry lenses: [ { order: 0 From 1d897ee7085c21feeaa656baee7ac21cca96d29f Mon Sep 17 00:00:00 2001 From: Javier Cevallos Date: Thu, 10 Oct 2024 15:34:44 -0700 Subject: [PATCH 02/17] fix: secure variable migration token (#3394) ## Description Closes #3172 fix: add secure validation to migrationToken parameter Implement input validation for the migrationToken parameter in the Bicep template to ensure only authorized tokens are accepted. This prevents potential misuse of the parameter and enhances the security of the deployment process. ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cognitive-services.account](https://github.com/jceval/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=fix%2Fsecure_variable_migration_token)](https://github.com/jceval/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/cognitive-services/account/main.bicep | 1 + avm/res/cognitive-services/account/main.json | 10 +++++----- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index eb12753477..d7c788c144 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -102,6 +102,7 @@ param customerManagedKey customerManagedKeyType @description('Optional. The flag to enable dynamic throttling.') param dynamicThrottlingEnabled bool = false +@secure() @description('Optional. Resource migration token.') param migrationToken string? diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 27a5d3ba80..7f45a5e8dc 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "259342811715055071" + "version": "0.30.23.60470", + "templateHash": "325704537018634474" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -795,7 +795,7 @@ } }, "migrationToken": { - "type": "string", + "type": "securestring", "nullable": true, "metadata": { "description": "Optional. Resource migration token." @@ -1784,8 +1784,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "986606208324987345" + "version": "0.30.23.60470", + "templateHash": "12263717469683062316" } }, "definitions": { From 0238a6722c029f35d6c8f2996d2f6f43316d1166 Mon Sep 17 00:00:00 2001 From: hundredacres Date: Thu, 10 Oct 2024 23:57:40 -0700 Subject: [PATCH 03/17] fix: Add support for forced tunneling (#3373) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Description Adds param to enable forcedTunneling, which adds a managementIPAddress. Fixes #3368 Closes #3368 ## Pipeline Reference | Pipeline | | -------- | [![avm.res.network.azure-firewall](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml/badge.svg?branch=fix%2Fissues%2F3368)](https://github.com/hundredacres/bicep-registry-modules/actions/workflows/avm.res.network.azure-firewall.yml) ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [X] Azure Verified Module updates: - [X] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [X] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [X] I'm sure there are no other open Pull Requests for the same update/change - [X] I have run `Set-AVMModule` locally to generate the supporting module files. - [X] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Máté Barabás Co-authored-by: Rainer Halanek <61878316+rahalan@users.noreply.github.com> Co-authored-by: JFolberth --- avm/res/network/azure-firewall/README.md | 128 +++++++++++++++++- avm/res/network/azure-firewall/main.bicep | 11 +- avm/res/network/azure-firewall/main.json | 29 ++-- .../tests/e2e/tunneling/dependencies.bicep | 59 ++++++++ .../tests/e2e/tunneling/main.test.bicep | 70 ++++++++++ 5 files changed, 278 insertions(+), 19 deletions(-) create mode 100644 avm/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep create mode 100644 avm/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep diff --git a/avm/res/network/azure-firewall/README.md b/avm/res/network/azure-firewall/README.md index 5d8d346c88..282958f330 100644 --- a/avm/res/network/azure-firewall/README.md +++ b/avm/res/network/azure-firewall/README.md @@ -18,7 +18,7 @@ This module deploys an Azure Firewall. | `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | | `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | | `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | -| `Microsoft.Network/azureFirewalls` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/azureFirewalls) | +| `Microsoft.Network/azureFirewalls` | [2024-01-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/azureFirewalls) | | `Microsoft.Network/publicIPAddresses` | [2023-09-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-09-01/publicIPAddresses) | ## Usage examples @@ -37,7 +37,8 @@ The following section provides usage examples for the module, which were used to - [Hub-min](#example-6-hub-min) - [Using large parameter set](#example-7-using-large-parameter-set) - [Public-IP-Prefix](#example-8-public-ip-prefix) -- [WAF-aligned](#example-9-waf-aligned) +- [Forced tunneling](#example-9-forced-tunneling) +- [WAF-aligned](#example-10-waf-aligned) ### Example 1: _Add-PIP_ @@ -1295,7 +1296,117 @@ param zones = []

-### Example 9: _WAF-aligned_ +### Example 9: _Forced tunneling_ + +This instance deploys the module and sets up forced tunneling. + + +

+ +via Bicep module + +```bicep +module azureFirewall 'br/public:avm/res/network/azure-firewall:' = { + name: 'azureFirewallDeployment' + params: { + // Required parameters + name: 'naftunn001' + // Non-required parameters + additionalPublicIpConfigurations: [ + { + name: 'ipConfig01' + publicIPAddressResourceId: '' + } + ] + azureSkuTier: 'Standard' + enableForcedTunneling: true + location: '' + managementIPAddressObject: { + publicIPAllocationMethod: 'Static' + } + virtualNetworkResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "naftunn001" + }, + // Non-required parameters + "additionalPublicIpConfigurations": { + "value": [ + { + "name": "ipConfig01", + "publicIPAddressResourceId": "" + } + ] + }, + "azureSkuTier": { + "value": "Standard" + }, + "enableForcedTunneling": { + "value": true + }, + "location": { + "value": "" + }, + "managementIPAddressObject": { + "value": { + "publicIPAllocationMethod": "Static" + } + }, + "virtualNetworkResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/network/azure-firewall:' + +// Required parameters +param name = 'naftunn001' +// Non-required parameters +param additionalPublicIpConfigurations = [ + { + name: 'ipConfig01' + publicIPAddressResourceId: '' + } +] +param azureSkuTier = 'Standard' +param enableForcedTunneling = true +param location = '' +param managementIPAddressObject = { + publicIPAllocationMethod: 'Static' +} +param virtualNetworkResourceId = '' +``` + +
+

+ +### Example 10: _WAF-aligned_ This instance deploys the module in alignment with the best-practices of the Azure Well-Architected Framework. @@ -1718,6 +1829,7 @@ param zones = [ | [`applicationRuleCollections`](#parameter-applicationrulecollections) | array | Collection of application rule collections used by Azure Firewall. | | [`azureSkuTier`](#parameter-azureskutier) | string | Tier of an Azure Firewall. | | [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The diagnostic settings of the service. | +| [`enableForcedTunneling`](#parameter-enableforcedtunneling) | bool | Enable/Disable forced tunneling. | | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | | [`firewallPolicyId`](#parameter-firewallpolicyid) | string | Resource ID of the Firewall Policy that should be attached. | | [`location`](#parameter-location) | string | Location for all resources. | @@ -2111,6 +2223,14 @@ Resource ID of the diagnostic log analytics workspace. For security reasons, it - Required: No - Type: string +### Parameter: `enableForcedTunneling` + +Enable/Disable forced tunneling. + +- Required: No +- Type: bool +- Default: `False` + ### Parameter: `enableTelemetry` Enable/Disable usage telemetry for module. @@ -2713,7 +2833,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/public-ip-address:0.5.1` | Remote reference | +| `br/public:avm/res/network/public-ip-address:0.6.0` | Remote reference | ## Data Collection diff --git a/avm/res/network/azure-firewall/main.bicep b/avm/res/network/azure-firewall/main.bicep index dc6a94ce87..39fd9b8fc0 100644 --- a/avm/res/network/azure-firewall/main.bicep +++ b/avm/res/network/azure-firewall/main.bicep @@ -66,6 +66,9 @@ param zones array = [ 3 ] +@description('Optional. Enable/Disable forced tunneling.') +param enableForcedTunneling bool = false + @description('Optional. The diagnostic settings of the service.') param diagnosticSettings diagnosticSettingType @@ -85,7 +88,7 @@ param tags object? param enableTelemetry bool = true var azureSkuName = empty(virtualNetworkResourceId) ? 'AZFW_Hub' : 'AZFW_VNet' -var requiresManagementIp = azureSkuTier == 'Basic' ? true : false +var requiresManagementIp = (azureSkuTier == 'Basic' || enableForcedTunneling) ? true : false var isCreateDefaultManagementIP = empty(managementIPResourceID) && requiresManagementIp // ---------------------------------------------------------------------------- @@ -193,7 +196,7 @@ resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableT } } -module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = if (empty(publicIPResourceID) && azureSkuName == 'AZFW_VNet') { +module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.6.0' = if (empty(publicIPResourceID) && azureSkuName == 'AZFW_VNet') { name: '${uniqueString(deployment().name, location)}-Firewall-PIP' params: { name: publicIPAddressObject.name @@ -224,7 +227,7 @@ module publicIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = if } // create a Management Public IP address if one is not provided and the flag is true -module managementIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = if (isCreateDefaultManagementIP && azureSkuName == 'AZFW_VNet') { +module managementIPAddress 'br/public:avm/res/network/public-ip-address:0.6.0' = if (isCreateDefaultManagementIP && azureSkuName == 'AZFW_VNet') { name: '${uniqueString(deployment().name, location)}-Firewall-MIP' params: { name: contains(managementIPAddressObject, 'name') @@ -257,7 +260,7 @@ module managementIPAddress 'br/public:avm/res/network/public-ip-address:0.5.1' = } } -resource azureFirewall 'Microsoft.Network/azureFirewalls@2023-04-01' = { +resource azureFirewall 'Microsoft.Network/azureFirewalls@2024-01-01' = { name: name location: location zones: length(zones) == 0 ? null : zones diff --git a/avm/res/network/azure-firewall/main.json b/avm/res/network/azure-firewall/main.json index 75a9bfba6a..43d731614e 100644 --- a/avm/res/network/azure-firewall/main.json +++ b/avm/res/network/azure-firewall/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "1087268001408720205" + "version": "0.30.3.12046", + "templateHash": "7724811109136350489" }, "name": "Azure Firewalls", "description": "This module deploys an Azure Firewall.", @@ -791,6 +791,13 @@ "description": "Optional. Zone numbers e.g. 1,2,3." } }, + "enableForcedTunneling": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable/Disable forced tunneling." + } + }, "diagnosticSettings": { "$ref": "#/definitions/diagnosticSettingType", "metadata": { @@ -850,7 +857,7 @@ } ], "azureSkuName": "[if(empty(parameters('virtualNetworkResourceId')), 'AZFW_Hub', 'AZFW_VNet')]", - "requiresManagementIp": "[if(equals(parameters('azureSkuTier'), 'Basic'), true(), false())]", + "requiresManagementIp": "[if(or(equals(parameters('azureSkuTier'), 'Basic'), parameters('enableForcedTunneling')), true(), false())]", "isCreateDefaultManagementIP": "[and(empty(parameters('managementIPResourceID')), variables('requiresManagementIp'))]", "builtInRoleNames": { "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", @@ -883,7 +890,7 @@ }, "azureFirewall": { "type": "Microsoft.Network/azureFirewalls", - "apiVersion": "2023-04-01", + "apiVersion": "2024-01-01", "name": "[parameters('name')]", "location": "[parameters('location')]", "zones": "[if(equals(length(parameters('zones')), 0), null(), parameters('zones'))]", @@ -1017,7 +1024,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "14450344965065009842" + "templateHash": "16693645977675862540" }, "name": "Public IP Addresses", "description": "This module deploys a Public IP Address.", @@ -1466,7 +1473,7 @@ "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { @@ -1474,7 +1481,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.5.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.6.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1670,7 +1677,7 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "14450344965065009842" + "templateHash": "16693645977675862540" }, "name": "Public IP Addresses", "description": "This module deploys a Public IP Address.", @@ -2119,7 +2126,7 @@ "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { @@ -2127,7 +2134,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.5.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-publicipaddress.{0}.{1}', replace('0.6.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -2345,7 +2352,7 @@ "metadata": { "description": "The location the resource was deployed into." }, - "value": "[reference('azureFirewall', '2023-04-01', 'full').location]" + "value": "[reference('azureFirewall', '2024-01-01', 'full').location]" } } } \ No newline at end of file diff --git a/avm/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep b/avm/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep new file mode 100644 index 0000000000..8497ceafc0 --- /dev/null +++ b/avm/res/network/azure-firewall/tests/e2e/tunneling/dependencies.bicep @@ -0,0 +1,59 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +@description('Required. The name of the Public IP to create.') +param publicIPName string + +var addressPrefix = '10.0.0.0/16' + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2023-04-01' = { + name: virtualNetworkName + location: location + properties: { + addressSpace: { + addressPrefixes: [ + addressPrefix + ] + } + subnets: [ + { + name: 'AzureFirewallSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 0) + } + } + { + name: 'AzureFirewallManagementSubnet' + properties: { + addressPrefix: cidrSubnet(addressPrefix, 26, 1) + } + } + ] + } +} + +resource publicIP 'Microsoft.Network/publicIPAddresses@2023-04-01' = { + name: publicIPName + location: location + sku: { + name: 'Standard' + tier: 'Regional' + } + properties: { + publicIPAllocationMethod: 'Static' + } + zones: [ + '1' + '2' + '3' + ] +} + +@description('The resource ID of the created Virtual Network.') +output virtualNetworkResourceId string = virtualNetwork.id + +@description('The resource ID of the created Public IP.') +output publicIPResourceId string = publicIP.id diff --git a/avm/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep b/avm/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep new file mode 100644 index 0000000000..8f70451dc2 --- /dev/null +++ b/avm/res/network/azure-firewall/tests/e2e/tunneling/main.test.bicep @@ -0,0 +1,70 @@ +targetScope = 'subscription' + +metadata name = 'Forced tunneling' +metadata description = 'This instance deploys the module and sets up forced tunneling.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-network.azurefirewalls-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'naftunn' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + publicIPName: 'dep-${namePrefix}-pip-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + location: resourceLocation + name: '${namePrefix}${serviceShort}001' + virtualNetworkResourceId: nestedDependencies.outputs.virtualNetworkResourceId + additionalPublicIpConfigurations: [ + { + name: 'ipConfig01' + publicIPAddressResourceId: nestedDependencies.outputs.publicIPResourceId + } + ] + azureSkuTier: 'Standard' + enableForcedTunneling: true + managementIPAddressObject: { + publicIPAllocationMethod: 'Static' + } + } + } +] From b03a1a7afe8cba76e62a0d538c0a7acab308e170 Mon Sep 17 00:00:00 2001 From: "Shihua Xiong (MSFT)" <138103031+NanaXiong00@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:15:32 +0800 Subject: [PATCH 04/17] feat: Add new ptn modules `avm/ptn/azd/acr-container-app` (#3234) ## Description Fixes https://github.com/Azure/Azure-Verified-Modules/issues/1221 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.acr-container-app](https://github.com/NanaXiong00/bicep-registry-modules/actions/workflows/avm.ptn.azd.acr-container-app.yml/badge.svg?branch=ptn%2Fazd%2Fcontainer-app)](https://github.com/NanaXiong00/bicep-registry-modules/actions/workflows/avm.ptn.azd.acr-container-app.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .../avm.ptn.azd.acr-container-app.yml | 88 + avm/ptn/azd/acr-container-app/README.md | 497 +++++ avm/ptn/azd/acr-container-app/main.bicep | 253 +++ avm/ptn/azd/acr-container-app/main.json | 1773 +++++++++++++++++ .../modules/registry-access.bicep | 32 + .../tests/e2e/defaults/dependencies.bicep | 14 + .../tests/e2e/defaults/main.test.bicep | 58 + avm/ptn/azd/acr-container-app/version.json | 7 + 10 files changed, 2724 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.acr-container-app.yml create mode 100644 avm/ptn/azd/acr-container-app/README.md create mode 100644 avm/ptn/azd/acr-container-app/main.bicep create mode 100644 avm/ptn/azd/acr-container-app/main.json create mode 100644 avm/ptn/azd/acr-container-app/modules/registry-access.bicep create mode 100644 avm/ptn/azd/acr-container-app/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/ptn/azd/acr-container-app/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/acr-container-app/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5ccd0ea12d..3c01853658 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -12,6 +12,7 @@ #/avm/ptn/avd-lza/management-plane/ @Azure/avm-ptn-avd-lza-managementplane-module-owners-bicep @Azure/avm-module-reviewers-bicep #/avm/ptn/avd-lza/networking/ @Azure/avm-ptn-avd-lza-networking-module-owners-bicep @Azure/avm-module-reviewers-bicep #/avm/ptn/avd-lza/session-hosts/ @Azure/avm-ptn-avd-lza-sessionhosts-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/acr-container-app/ @Azure/avm-ptn-azd-acrcontainerapp-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 486e96195c..5beb6c6247 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -47,6 +47,7 @@ body: # - "avm/ptn/avd-lza/management-plane" # - "avm/ptn/avd-lza/networking" # - "avm/ptn/avd-lza/session-hosts" + - "avm/ptn/azd/acr-container-app" - "avm/ptn/azd/apim-api" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" diff --git a/.github/workflows/avm.ptn.azd.acr-container-app.yml b/.github/workflows/avm.ptn.azd.acr-container-app.yml new file mode 100644 index 0000000000..04a83ea855 --- /dev/null +++ b/.github/workflows/avm.ptn.azd.acr-container-app.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.acr-container-app" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.acr-container-app.yml" + - "avm/ptn/azd/acr-container-app/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/acr-container-app" + workflowPath: ".github/workflows/avm.ptn.azd.acr-container-app.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/ptn/azd/acr-container-app/README.md b/avm/ptn/azd/acr-container-app/README.md new file mode 100644 index 0000000000..a2a8f79199 --- /dev/null +++ b/avm/ptn/azd/acr-container-app/README.md @@ -0,0 +1,497 @@ +# Azd ACR Linked Container App `[Azd/AcrContainerApp]` + +Creates a container app in an Azure Container App environment. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.App/containerApps` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.App/2024-03-01/containerApps) | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/azd/acr-container-app:`. + +- [Using only defaults](#example-1-using-only-defaults) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module acrContainerApp 'br/public:avm/ptn/azd/acr-container-app:' = { + name: 'acrContainerAppDeployment' + params: { + // Required parameters + containerAppsEnvironmentName: '' + name: 'acamin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

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

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/acr-container-app:' + +// Required parameters +param containerAppsEnvironmentName = '' +param name = 'acamin001' +// Non-required parameters +param location = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containerAppsEnvironmentName`](#parameter-containerappsenvironmentname) | string | Name of the environment for container apps. | +| [`name`](#parameter-name) | string | The name of the Container App. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`allowedOrigins`](#parameter-allowedorigins) | array | Allowed origins. | +| [`containerCpuCoreCount`](#parameter-containercpucorecount) | string | CPU cores allocated to a single container instance, e.g., 0.5. | +| [`containerMaxReplicas`](#parameter-containermaxreplicas) | int | The maximum number of replicas to run. Must be at least 1. | +| [`containerMemory`](#parameter-containermemory) | string | Memory allocated to a single container instance, e.g., 1Gi. | +| [`containerMinReplicas`](#parameter-containerminreplicas) | int | The minimum number of replicas to run. Must be at least 2. | +| [`containerName`](#parameter-containername) | string | The name of the container. | +| [`containerRegistryHostSuffix`](#parameter-containerregistryhostsuffix) | string | Hostname suffix for container registry. Set when deploying to sovereign clouds. | +| [`containerRegistryName`](#parameter-containerregistryname) | string | The name of the container registry. | +| [`daprAppId`](#parameter-daprappid) | string | The Dapr app ID. | +| [`daprAppProtocol`](#parameter-daprappprotocol) | string | The protocol used by Dapr to connect to the app, e.g., http or grpc. | +| [`daprEnabled`](#parameter-daprenabled) | bool | Enable Dapr. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`env`](#parameter-env) | array | The environment variables for the container. | +| [`external`](#parameter-external) | bool | Specifies if the resource ingress is exposed externally. | +| [`identityName`](#parameter-identityname) | string | The name of the user-assigned identity. | +| [`identityType`](#parameter-identitytype) | string | The type of identity for the resource. | +| [`imageName`](#parameter-imagename) | string | The name of the container image. | +| [`includeAddOns`](#parameter-includeaddons) | bool | Toggle to include the service configuration. | +| [`ingressAllowInsecure`](#parameter-ingressallowinsecure) | bool | Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections. | +| [`ingressEnabled`](#parameter-ingressenabled) | bool | Specifies if Ingress is enabled for the container app. | +| [`ingressTransport`](#parameter-ingresstransport) | string | Ingress transport protocol. | +| [`ipSecurityRestrictions`](#parameter-ipsecurityrestrictions) | array | Rules to restrict incoming IP address. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`principalId`](#parameter-principalid) | string | The principal ID of the principal to assign the role to. | +| [`revisionMode`](#parameter-revisionmode) | string | Controls how active revisions are handled for the Container app. | +| [`secrets`](#parameter-secrets) | secureObject | The secrets required for the container. | +| [`serviceBinds`](#parameter-servicebinds) | array | The service binds associated with the container. | +| [`serviceType`](#parameter-servicetype) | string | The name of the container apps add-on to use. e.g. redis. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`targetPort`](#parameter-targetport) | int | The target port for the container. | +| [`userAssignedIdentityResourceId`](#parameter-userassignedidentityresourceid) | string | The resource id of the user-assigned identity. | + +### Parameter: `containerAppsEnvironmentName` + +Name of the environment for container apps. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the Container App. + +- Required: Yes +- Type: string + +### Parameter: `allowedOrigins` + +Allowed origins. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `containerCpuCoreCount` + +CPU cores allocated to a single container instance, e.g., 0.5. + +- Required: No +- Type: string +- Default: `'0.5'` + +### Parameter: `containerMaxReplicas` + +The maximum number of replicas to run. Must be at least 1. + +- Required: No +- Type: int +- Default: `10` + +### Parameter: `containerMemory` + +Memory allocated to a single container instance, e.g., 1Gi. + +- Required: No +- Type: string +- Default: `'1.0Gi'` + +### Parameter: `containerMinReplicas` + +The minimum number of replicas to run. Must be at least 2. + +- Required: No +- Type: int +- Default: `2` + +### Parameter: `containerName` + +The name of the container. + +- Required: No +- Type: string +- Default: `'main'` + +### Parameter: `containerRegistryHostSuffix` + +Hostname suffix for container registry. Set when deploying to sovereign clouds. + +- Required: No +- Type: string +- Default: `'azurecr.io'` + +### Parameter: `containerRegistryName` + +The name of the container registry. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `daprAppId` + +The Dapr app ID. + +- Required: No +- Type: string +- Default: `[parameters('containerName')]` + +### Parameter: `daprAppProtocol` + +The protocol used by Dapr to connect to the app, e.g., http or grpc. + +- Required: No +- Type: string +- Default: `'http'` +- Allowed: + ```Bicep + [ + 'grpc' + 'http' + ] + ``` + +### Parameter: `daprEnabled` + +Enable Dapr. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `env` + +The environment variables for the container. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-envname) | string | Environment variable name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`secretRef`](#parameter-envsecretref) | string | Name of the Container App secret from which to pull the environment variable value. | +| [`value`](#parameter-envvalue) | string | Non-secret environment variable value. | + +### Parameter: `env.name` + +Environment variable name. + +- Required: Yes +- Type: string + +### Parameter: `env.secretRef` + +Name of the Container App secret from which to pull the environment variable value. + +- Required: No +- Type: string + +### Parameter: `env.value` + +Non-secret environment variable value. + +- Required: No +- Type: string + +### Parameter: `external` + +Specifies if the resource ingress is exposed externally. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `identityName` + +The name of the user-assigned identity. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `identityType` + +The type of identity for the resource. + +- Required: No +- Type: string +- Default: `'None'` +- Allowed: + ```Bicep + [ + 'None' + 'SystemAssigned' + 'UserAssigned' + ] + ``` + +### Parameter: `imageName` + +The name of the container image. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `includeAddOns` + +Toggle to include the service configuration. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `ingressAllowInsecure` + +Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `ingressEnabled` + +Specifies if Ingress is enabled for the container app. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `ingressTransport` + +Ingress transport protocol. + +- Required: No +- Type: string +- Default: `'auto'` +- Allowed: + ```Bicep + [ + 'auto' + 'http' + 'http2' + 'tcp' + ] + ``` + +### Parameter: `ipSecurityRestrictions` + +Rules to restrict incoming IP address. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `principalId` + +The principal ID of the principal to assign the role to. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `revisionMode` + +Controls how active revisions are handled for the Container app. + +- Required: No +- Type: string +- Default: `'Single'` +- Allowed: + ```Bicep + [ + 'Multiple' + 'Single' + ] + ``` + +### Parameter: `secrets` + +The secrets required for the container. + +- Required: No +- Type: secureObject +- Default: `{}` + +### Parameter: `serviceBinds` + +The service binds associated with the container. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `serviceType` + +The name of the container apps add-on to use. e.g. redis. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `targetPort` + +The target port for the container. + +- Required: No +- Type: int +- Default: `80` + +### Parameter: `userAssignedIdentityResourceId` + +The resource id of the user-assigned identity. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `defaultDomain` | string | The Default domain of the Managed Environment. | +| `identityPrincipalId` | string | The principal ID of the identity. | +| `imageName` | string | The name of the container image. | +| `name` | string | The name of the Container App. | +| `resourceGroupName` | string | The name of the resource group the Container App was deployed into. | +| `resourceId` | string | The resource ID of the Container App. | +| `serviceBind` | object | The service binds associated with the container. | +| `uri` | string | The uri of the Container App. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/ptn/authorization/resource-role-assignment:0.1.1` | Remote reference | +| `br/public:avm/res/app/container-app:0.10.0` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/ptn/azd/acr-container-app/main.bicep b/avm/ptn/azd/acr-container-app/main.bicep new file mode 100644 index 0000000000..2f600aacf9 --- /dev/null +++ b/avm/ptn/azd/acr-container-app/main.bicep @@ -0,0 +1,253 @@ +metadata name = 'Azd ACR Linked Container App' +metadata description = '''Creates a container app in an Azure Container App environment. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the Container App.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Optional. Allowed origins.') +param allowedOrigins array = [] + +@description('Required. Name of the environment for container apps.') +param containerAppsEnvironmentName string + +@description('Optional. CPU cores allocated to a single container instance, e.g., 0.5.') +param containerCpuCoreCount string = '0.5' + +@description('Optional. The maximum number of replicas to run. Must be at least 1.') +@minValue(1) +param containerMaxReplicas int = 10 + +@description('Optional. Memory allocated to a single container instance, e.g., 1Gi.') +param containerMemory string = '1.0Gi' + +@description('Optional. The minimum number of replicas to run. Must be at least 2.') +param containerMinReplicas int = 2 + +@description('Optional. The name of the container.') +param containerName string = 'main' + +@description('Optional. The name of the container registry.') +param containerRegistryName string = '' + +@description('Optional. Hostname suffix for container registry. Set when deploying to sovereign clouds.') +param containerRegistryHostSuffix string = 'azurecr.io' + +@description('Optional. The protocol used by Dapr to connect to the app, e.g., http or grpc.') +@allowed(['http', 'grpc']) +param daprAppProtocol string = 'http' + +@description('Optional. The Dapr app ID.') +param daprAppId string = containerName + +@description('Optional. Enable Dapr.') +param daprEnabled bool = false + +@description('Optional. The environment variables for the container.') +param env environmentType[]? + +@description('Optional. Specifies if the resource ingress is exposed externally.') +param external bool = true + +@description('Optional. The name of the user-assigned identity.') +param identityName string = '' + +@description('Optional. The type of identity for the resource.') +@allowed(['None', 'SystemAssigned', 'UserAssigned']) +param identityType string = 'None' + +@description('Optional. The name of the container image.') +param imageName string = '' + +@description('Optional. Specifies if Ingress is enabled for the container app.') +param ingressEnabled bool = true + +@allowed([ + 'auto' + 'http' + 'http2' + 'tcp' +]) +@description('Optional. Ingress transport protocol.') +param ingressTransport string = 'auto' + +@description('Optional. Rules to restrict incoming IP address.') +param ipSecurityRestrictions array = [] + +@description('Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections.') +param ingressAllowInsecure bool = true + +@allowed([ + 'Multiple' + 'Single' +]) +@description('Optional. Controls how active revisions are handled for the Container app.') +param revisionMode string = 'Single' + +@description('Optional. The secrets required for the container.') +@secure() +param secrets object = {} + +@description('Optional. The service binds associated with the container.') +param serviceBinds array = [] + +@description('Optional. The name of the container apps add-on to use. e.g. redis.') +param serviceType string = '' + +@description('Optional. The target port for the container.') +param targetPort int = 80 + +@description('Optional. Toggle to include the service configuration.') +param includeAddOns bool = false + +@description('Optional. The principal ID of the principal to assign the role to.') +param principalId string = '' + +@description('Optional. The resource id of the user-assigned identity.') +param userAssignedIdentityResourceId string = '' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +// Private registry support requires both an ACR name and a User Assigned managed identity +var usePrivateRegistry = !empty(identityName) && !empty(containerRegistryName) + +// Automatically set to `UserAssigned` when an `identityName` has been set +var normalizedIdentityType = !empty(identityName) ? 'UserAssigned' : identityType + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.azd-acrcontainerapp.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +module containerApp 'br/public:avm/res/app/container-app:0.10.0' = { + name: '${uniqueString(deployment().name, location)}-container-app' + params: { + name: name + location: location + tags: tags + managedIdentities: !empty(identityName) && normalizedIdentityType == 'UserAssigned' + ? { userAssignedResourceIds: [userAssignedIdentityResourceId] } + : { systemAssigned: normalizedIdentityType == 'SystemAssigned' } + environmentResourceId: containerAppsEnvironment.id + activeRevisionsMode: revisionMode + disableIngress: !ingressEnabled + ingressExternal: external + ingressTargetPort: targetPort + ingressTransport: ingressTransport + ipSecurityRestrictions: ipSecurityRestrictions + ingressAllowInsecure: ingressAllowInsecure + corsPolicy: { + allowedOrigins: union(['https://portal.azure.com', 'https://ms.portal.azure.com'], allowedOrigins) + } + dapr: daprEnabled + ? { + enabled: true + appId: daprAppId + appProtocol: daprAppProtocol + appPort: ingressEnabled ? targetPort : 0 + } + : { enabled: false } + secrets: secrets + includeAddOns: includeAddOns + service: { type: serviceType } + registries: usePrivateRegistry + ? [ + { + server: '${containerRegistryName}.${containerRegistryHostSuffix}' + identity: userAssignedIdentityResourceId + } + ] + : [] + serviceBinds: serviceBinds + containers: [ + { + image: !empty(imageName) ? imageName : 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + name: containerName + env: env + resources: { + cpu: json(containerCpuCoreCount) + memory: containerMemory + } + } + ] + scaleMaxReplicas: containerMaxReplicas + scaleMinReplicas: containerMinReplicas + enableTelemetry: enableTelemetry + } + dependsOn: usePrivateRegistry ? [containerRegistryAccess] : [] +} + +module containerRegistryAccess 'modules/registry-access.bicep' = if (usePrivateRegistry) { + name: '${uniqueString(deployment().name, location)}-registry-access' + params: { + containerRegistryName: containerRegistryName + principalId: usePrivateRegistry ? principalId : '' + enableTelemetry: enableTelemetry + } +} + +resource containerAppsEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' existing = { + name: containerAppsEnvironmentName +} + +@description('The name of the resource group the Container App was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The Default domain of the Managed Environment.') +output defaultDomain string = containerAppsEnvironment.properties.defaultDomain + +@description('The principal ID of the identity.') +output identityPrincipalId string = normalizedIdentityType == 'None' + ? '' + : (empty(identityName) ? containerApp.outputs.systemAssignedMIPrincipalId : principalId) + +@description('The name of the container image.') +output imageName string = imageName + +@description('The name of the Container App.') +output name string = containerApp.outputs.name + +@description('The service binds associated with the container.') +output serviceBind object = !empty(serviceType) + ? { serviceId: containerApp.outputs.resourceId, name: containerApp.outputs.name } + : {} + +@description('The uri of the Container App.') +output uri string = ingressEnabled ? 'https://${containerApp.outputs.fqdn}' : '' + +@description('The resource ID of the Container App.') +output resourceId string = containerApp.outputs.resourceId + +type environmentType = { + @description('Required. Environment variable name.') + name: string + + @description('Optional. Name of the Container App secret from which to pull the environment variable value.') + secretRef: string? + + @description('Optional. Non-secret environment variable value.') + value: string? +} diff --git a/avm/ptn/azd/acr-container-app/main.json b/avm/ptn/azd/acr-container-app/main.json new file mode 100644 index 0000000000..3aa2261a84 --- /dev/null +++ b/avm/ptn/azd/acr-container-app/main.json @@ -0,0 +1,1773 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "8683355263365484382" + }, + "name": "Azd ACR Linked Container App", + "description": "Creates a container app in an Azure Container App environment.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "environmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "allowedOrigins": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Allowed origins." + } + }, + "containerAppsEnvironmentName": { + "type": "string", + "metadata": { + "description": "Required. Name of the environment for container apps." + } + }, + "containerCpuCoreCount": { + "type": "string", + "defaultValue": "0.5", + "metadata": { + "description": "Optional. CPU cores allocated to a single container instance, e.g., 0.5." + } + }, + "containerMaxReplicas": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "metadata": { + "description": "Optional. The maximum number of replicas to run. Must be at least 1." + } + }, + "containerMemory": { + "type": "string", + "defaultValue": "1.0Gi", + "metadata": { + "description": "Optional. Memory allocated to a single container instance, e.g., 1Gi." + } + }, + "containerMinReplicas": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. The minimum number of replicas to run. Must be at least 2." + } + }, + "containerName": { + "type": "string", + "defaultValue": "main", + "metadata": { + "description": "Optional. The name of the container." + } + }, + "containerRegistryName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container registry." + } + }, + "containerRegistryHostSuffix": { + "type": "string", + "defaultValue": "azurecr.io", + "metadata": { + "description": "Optional. Hostname suffix for container registry. Set when deploying to sovereign clouds." + } + }, + "daprAppProtocol": { + "type": "string", + "defaultValue": "http", + "allowedValues": [ + "http", + "grpc" + ], + "metadata": { + "description": "Optional. The protocol used by Dapr to connect to the app, e.g., http or grpc." + } + }, + "daprAppId": { + "type": "string", + "defaultValue": "[parameters('containerName')]", + "metadata": { + "description": "Optional. The Dapr app ID." + } + }, + "daprEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable Dapr." + } + }, + "env": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The environment variables for the container." + } + }, + "external": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the resource ingress is exposed externally." + } + }, + "identityName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the user-assigned identity." + } + }, + "identityType": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "None", + "SystemAssigned", + "UserAssigned" + ], + "metadata": { + "description": "Optional. The type of identity for the resource." + } + }, + "imageName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container image." + } + }, + "ingressEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if Ingress is enabled for the container app." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Rules to restrict incoming IP address." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "revisionMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "secrets": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The secrets required for the container." + } + }, + "serviceBinds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The service binds associated with the container." + } + }, + "serviceType": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container apps add-on to use. e.g. redis." + } + }, + "targetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. The target port for the container." + } + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "principalId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The principal ID of the principal to assign the role to." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource id of the user-assigned identity." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "usePrivateRegistry": "[and(not(empty(parameters('identityName'))), not(empty(parameters('containerRegistryName'))))]", + "normalizedIdentityType": "[if(not(empty(parameters('identityName'))), 'UserAssigned', parameters('identityType'))]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-acrcontainerapp.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "containerAppsEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2023-05-01", + "name": "[parameters('containerAppsEnvironmentName')]" + }, + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-container-app', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": "[if(and(not(empty(parameters('identityName'))), equals(variables('normalizedIdentityType'), 'UserAssigned')), createObject('value', createObject('userAssignedResourceIds', createArray(parameters('userAssignedIdentityResourceId')))), createObject('value', createObject('systemAssigned', equals(variables('normalizedIdentityType'), 'SystemAssigned'))))]", + "environmentResourceId": { + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('containerAppsEnvironmentName'))]" + }, + "activeRevisionsMode": { + "value": "[parameters('revisionMode')]" + }, + "disableIngress": { + "value": "[not(parameters('ingressEnabled'))]" + }, + "ingressExternal": { + "value": "[parameters('external')]" + }, + "ingressTargetPort": { + "value": "[parameters('targetPort')]" + }, + "ingressTransport": { + "value": "[parameters('ingressTransport')]" + }, + "ipSecurityRestrictions": { + "value": "[parameters('ipSecurityRestrictions')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": { + "value": { + "allowedOrigins": "[union(createArray('https://portal.azure.com', 'https://ms.portal.azure.com'), parameters('allowedOrigins'))]" + } + }, + "dapr": "[if(parameters('daprEnabled'), createObject('value', createObject('enabled', true(), 'appId', parameters('daprAppId'), 'appProtocol', parameters('daprAppProtocol'), 'appPort', if(parameters('ingressEnabled'), parameters('targetPort'), 0))), createObject('value', createObject('enabled', false())))]", + "secrets": { + "value": "[parameters('secrets')]" + }, + "includeAddOns": { + "value": "[parameters('includeAddOns')]" + }, + "service": { + "value": { + "type": "[parameters('serviceType')]" + } + }, + "registries": "[if(variables('usePrivateRegistry'), createObject('value', createArray(createObject('server', format('{0}.{1}', parameters('containerRegistryName'), parameters('containerRegistryHostSuffix')), 'identity', parameters('userAssignedIdentityResourceId')))), createObject('value', createArray()))]", + "serviceBinds": { + "value": "[parameters('serviceBinds')]" + }, + "containers": { + "value": [ + { + "image": "[if(not(empty(parameters('imageName'))), parameters('imageName'), 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest')]", + "name": "[parameters('containerName')]", + "env": "[parameters('env')]", + "resources": { + "cpu": "[json(parameters('containerCpuCoreCount'))]", + "memory": "[parameters('containerMemory')]" + } + } + ] + }, + "scaleMaxReplicas": { + "value": "[parameters('containerMaxReplicas')]" + }, + "scaleMinReplicas": { + "value": "[parameters('containerMinReplicas')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "9894768173968934379" + }, + "name": "Container Apps", + "description": "This module deploys a Container App.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "container": { + "type": "object", + "properties": { + "args": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container start command arguments." + } + }, + "command": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container start command." + } + }, + "env": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentVar" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container environment variables." + } + }, + "image": { + "type": "string", + "metadata": { + "description": "Required. Container image tag." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Custom container name." + } + }, + "probes": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbe" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of probes for the container." + } + }, + "resources": { + "type": "object", + "metadata": { + "description": "Required. Container resource requirements." + } + }, + "volumeMounts": { + "type": "array", + "items": { + "$ref": "#/definitions/volumeMount" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container volume mounts." + } + } + } + }, + "ingressPortMapping": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + } + }, + "serviceBind": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + } + }, + "environmentVar": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + } + }, + "containerAppProbe": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGet", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocket", + "nullable": true, + "metadata": { + "description": "Optional. TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "nullable": true + }, + "containerAppProbeHttpGet": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItem" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + } + }, + "containerAppProbeHttpGetHeadersItem": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + } + }, + "containerAppProbeTcpSocket": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + } + }, + "volumeMount": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dev ContainerApp service type." + } + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMapping" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": 10, + "metadata": { + "description": "Optional. Maximum number of container replicas. Defaults to 10 if not set." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": 3, + "metadata": { + "description": "Optional. Minimum number of container replicas. Defaults to 3 if not set." + } + }, + "scaleRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Scaling rules." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBind" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "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." + } + }, + "customDomains": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Custom domain bindings for Container App hostnames." + } + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Rules to restrict incoming IP address." + } + }, + "trafficLabel": { + "type": "string", + "defaultValue": "label-1", + "metadata": { + "description": "Optional. Associates a traffic label with a revision. Label name should be consist of lower case alphanumeric characters or dashes." + } + }, + "trafficLatestRevision": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates that the traffic weight belongs to a latest stable revision." + } + }, + "trafficRevisionName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of a revision." + } + }, + "trafficWeight": { + "type": "int", + "defaultValue": 100, + "metadata": { + "description": "Optional. Traffic weight assigned to a revision." + } + }, + "dapr": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dapr configuration for the Container App." + } + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/container" + }, + "metadata": { + "description": "Required. List of container definitions for the Container App." + } + }, + "initContainersTemplate": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of specialized containers that run before app containers." + } + }, + "secrets": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of volume definitions for the Container App." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "secretList": "[if(not(empty(parameters('secrets'))), parameters('secrets').secureList, createArray())]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "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": "2024-03-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.10.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" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-03-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[if(not(empty(parameters('dapr'))), parameters('dapr'), null())]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', if(not(empty(parameters('customDomains'))), parameters('customDomains'), null()), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', if(not(empty(parameters('ipSecurityRestrictions'))), parameters('ipSecurityRestrictions'), null()), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), createArray(createObject('label', parameters('trafficLabel'), 'latestRevision', parameters('trafficLatestRevision'), 'revisionName', parameters('trafficRevisionName'), 'weight', parameters('trafficWeight'))), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(and(parameters('includeAddOns'), not(empty(parameters('service')))), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[if(not(empty(parameters('registries'))), parameters('registries'), null())]", + "secrets": "[variables('secretList')]" + }, + "template": { + "containers": "[parameters('containers')]", + "initContainers": "[if(not(empty(parameters('initContainersTemplate'))), parameters('initContainersTemplate'), null())]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": { + "maxReplicas": "[parameters('scaleMaxReplicas')]", + "minReplicas": "[parameters('scaleMinReplicas')]", + "rules": "[if(not(empty(parameters('scaleRules'))), parameters('scaleRules'), null())]" + }, + "serviceBinds": "[if(and(parameters('includeAddOns'), not(empty(parameters('serviceBinds')))), parameters('serviceBinds'), null())]", + "volumes": "[if(not(empty(parameters('volumes'))), parameters('volumes'), null())]" + }, + "workloadProfileName": "[parameters('workloadProfileName')]" + } + }, + "containerApp_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.App/containerApps/{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": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.App/containerApps/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('containerApp', '2024-03-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2024-03-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "containerAppsEnvironment", + "containerRegistryAccess" + ] + }, + "containerRegistryAccess": { + "condition": "[variables('usePrivateRegistry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry-access', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerRegistryName": { + "value": "[parameters('containerRegistryName')]" + }, + "principalId": "[if(variables('usePrivateRegistry'), createObject('value', parameters('principalId')), createObject('value', ''))]", + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "9239508313239206967" + }, + "name": "ACR Pull permissions", + "description": "Assigns ACR Pull permissions to access an Azure Container Registry.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the container registry." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "acrPullRole": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "acrpullrole-deployment", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[parameters('principalId')]" + }, + "resourceId": { + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName'))]" + }, + "roleDefinitionId": { + "value": "[variables('acrPullRole')]" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "1847432691715853168" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The scope for the role assignment, fully qualified resourceId." + } + }, + "name": { + "type": "string", + "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "metadata": { + "description": "Optional. The unique guid name for the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition ID for the role assignment." + } + }, + "roleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name for the role, used for logging." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "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 role assignment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "principalType": "[[parameters('principalType')]", + "description": "[[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[parameters('resourceId')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "principalType": { + "value": "[parameters('principalType')]" + }, + "description": { + "value": "[parameters('description')]" + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[parameters('name')]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The name for the role, used for logging." + }, + "value": "[parameters('roleName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + ] + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Managed Environment." + }, + "value": "[reference('containerAppsEnvironment').defaultDomain]" + }, + "identityPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the identity." + }, + "value": "[if(equals(variables('normalizedIdentityType'), 'None'), '', if(empty(parameters('identityName')), reference('containerApp').outputs.systemAssignedMIPrincipalId.value, parameters('principalId')))]" + }, + "imageName": { + "type": "string", + "metadata": { + "description": "The name of the container image." + }, + "value": "[parameters('imageName')]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "serviceBind": { + "type": "object", + "metadata": { + "description": "The service binds associated with the container." + }, + "value": "[if(not(empty(parameters('serviceType'))), createObject('serviceId', reference('containerApp').outputs.resourceId.value, 'name', reference('containerApp').outputs.name.value), createObject())]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The uri of the Container App." + }, + "value": "[if(parameters('ingressEnabled'), format('https://{0}', reference('containerApp').outputs.fqdn.value), '')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/acr-container-app/modules/registry-access.bicep b/avm/ptn/azd/acr-container-app/modules/registry-access.bicep new file mode 100644 index 0000000000..3fdfe31799 --- /dev/null +++ b/avm/ptn/azd/acr-container-app/modules/registry-access.bicep @@ -0,0 +1,32 @@ +metadata name = 'ACR Pull permissions' +metadata description = 'Assigns ACR Pull permissions to access an Azure Container Registry.' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the container registry.') +param containerRegistryName string + +@description('Required. The principal ID of the principal (user/group/identity) to assign the role to.') +param principalId string + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var acrPullRole = subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7f951dda-4ed3-4680-a7ca-43fe172d538d' +) + +module aksAcrPull 'br/public:avm/ptn/authorization/resource-role-assignment:0.1.1' = { + name: 'acrpullrole-deployment' + params: { + principalId: principalId + resourceId: containerRegistry.id + roleDefinitionId: acrPullRole + principalType: 'ServicePrincipal' + enableTelemetry: enableTelemetry + } +} + +resource containerRegistry 'Microsoft.ContainerRegistry/registries@2023-01-01-preview' existing = { + name: containerRegistryName +} diff --git a/avm/ptn/azd/acr-container-app/tests/e2e/defaults/dependencies.bicep b/avm/ptn/azd/acr-container-app/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..6c93d0689b --- /dev/null +++ b/avm/ptn/azd/acr-container-app/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,14 @@ +@description('Required. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Environment to create.') +param managedEnvironmentName string + +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: managedEnvironmentName + location: location + properties: {} +} + +@description('The name of the Container Apps environment.') +output containerAppsEnvironmentName string = managedEnvironment.name diff --git a/avm/ptn/azd/acr-container-app/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/acr-container-app/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..caa47bc42f --- /dev/null +++ b/avm/ptn/azd/acr-container-app/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-azd-acrcontainerapp-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'acamin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedEnvironmentName: 'dep-${namePrefix}-me-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + containerAppsEnvironmentName: nestedDependencies.outputs.containerAppsEnvironmentName + location: resourceLocation + } + } +] diff --git a/avm/ptn/azd/acr-container-app/version.json b/avm/ptn/azd/acr-container-app/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/acr-container-app/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From 6b63b1051ff4e19261a414acc829f6278ac8c3a1 Mon Sep 17 00:00:00 2001 From: "Jianing Wang (MSFT)" <141212663+jianingwang123@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:21:21 +0800 Subject: [PATCH 05/17] feat: Add new ptn modules `avm/ptn/azd/monitoring` (#3255) ## Description Fixes [Azure/Azure-Verified-Modules/issues#1226](https://github.com/Azure/Azure-Verified-Modules/issues/1226) ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.monitoring](https://github.com/jianingwang123/bicep-registry-modules/actions/workflows/avm.ptn.azd.monitoring.yml/badge.svg?branch=fix%2F1226)](https://github.com/jianingwang123/bicep-registry-modules/actions/workflows/avm.ptn.azd.monitoring.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .github/workflows/avm.ptn.azd.monitoring.yml | 88 + avm/ptn/azd/monitoring/README.md | 208 + avm/ptn/azd/monitoring/main.bicep | 102 + avm/ptn/azd/monitoring/main.json | 4604 +++++++++++++++++ .../tests/e2e/defaults/main.test.bicep | 46 + avm/ptn/azd/monitoring/version.json | 7 + 8 files changed, 5057 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.monitoring.yml create mode 100644 avm/ptn/azd/monitoring/README.md create mode 100644 avm/ptn/azd/monitoring/main.bicep create mode 100644 avm/ptn/azd/monitoring/main.json create mode 100644 avm/ptn/azd/monitoring/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/monitoring/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 3c01853658..2167ffc054 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,6 +17,7 @@ /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/ml-hub-dependencies/ @Azure/avm-ptn-azd-mlhubdependencies-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/monitoring/ @Azure/avm-ptn-azd-monitoring-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/deployment-script/import-image-to-acr/ @Azure/avm-ptn-deploymentscript-importimagetoacr-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/dev-ops/cicd-agents-and-runners/ @Azure/avm-ptn-devops-cicdagentsandrunners-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/finops-toolkit/finops-hub/ @Azure/avm-ptn-finopstoolkit-finopshub-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 5beb6c6247..a74c246995 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -52,6 +52,7 @@ body: - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" - "avm/ptn/azd/ml-hub-dependencies" + - "avm/ptn/azd/monitoring" - "avm/ptn/deployment-script/import-image-to-acr" - "avm/ptn/dev-ops/cicd-agents-and-runners" - "avm/ptn/finops-toolkit/finops-hub" diff --git a/.github/workflows/avm.ptn.azd.monitoring.yml b/.github/workflows/avm.ptn.azd.monitoring.yml new file mode 100644 index 0000000000..bba2cd1314 --- /dev/null +++ b/.github/workflows/avm.ptn.azd.monitoring.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.monitoring" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.monitoring" + - "avm/ptn/azd/monitoring/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/monitoring" + workflowPath: ".github/workflows/avm.ptn.azd.monitoring.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit \ No newline at end of file diff --git a/avm/ptn/azd/monitoring/README.md b/avm/ptn/azd/monitoring/README.md new file mode 100644 index 0000000000..69f80aaf24 --- /dev/null +++ b/avm/ptn/azd/monitoring/README.md @@ -0,0 +1,208 @@ +# Azd Azure Monitoring `[Azd/Monitoring]` + +Creates an Application Insights instance and a Log Analytics workspace. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/components` | [2020-02-02](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2020-02-02/components) | +| `microsoft.insights/components/linkedStorageAccounts` | [2020-03-01-preview](https://learn.microsoft.com/en-us/azure/templates/microsoft.insights/2020-03-01-preview/components/linkedStorageAccounts) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.OperationalInsights/workspaces` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2022-10-01/workspaces) | +| `Microsoft.OperationalInsights/workspaces/dataExports` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/dataExports) | +| `Microsoft.OperationalInsights/workspaces/dataSources` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/dataSources) | +| `Microsoft.OperationalInsights/workspaces/linkedServices` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/linkedServices) | +| `Microsoft.OperationalInsights/workspaces/linkedStorageAccounts` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/linkedStorageAccounts) | +| `Microsoft.OperationalInsights/workspaces/savedSearches` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/savedSearches) | +| `Microsoft.OperationalInsights/workspaces/storageInsightConfigs` | [2020-08-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2020-08-01/workspaces/storageInsightConfigs) | +| `Microsoft.OperationalInsights/workspaces/tables` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationalInsights/2022-10-01/workspaces/tables) | +| `Microsoft.OperationsManagement/solutions` | [2015-11-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.OperationsManagement/2015-11-01-preview/solutions) | +| `Microsoft.Portal/dashboards` | [2020-09-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Portal/2020-09-01-preview/dashboards) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/azd/monitoring:`. + +- [Using only defaults](#example-1-using-only-defaults) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module monitoring 'br/public:avm/ptn/azd/monitoring:' = { + name: 'monitoringDeployment' + params: { + // Required parameters + applicationInsightsName: '' + logAnalyticsName: '' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

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

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/monitoring:' + +// Required parameters +param applicationInsightsName = '' +param logAnalyticsName = '' +// Non-required parameters +param location = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationInsightsName`](#parameter-applicationinsightsname) | string | The resource insights components name. | +| [`logAnalyticsName`](#parameter-loganalyticsname) | string | The resource operational insights workspaces name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`applicationInsightsDashboardName`](#parameter-applicationinsightsdashboardname) | string | The resource portal dashboards name. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `applicationInsightsName` + +The resource insights components name. + +- Required: Yes +- Type: string + +### Parameter: `logAnalyticsName` + +The resource operational insights workspaces name. + +- Required: Yes +- Type: string + +### Parameter: `applicationInsightsDashboardName` + +The resource portal dashboards name. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- Example: + ```Bicep + { + "key1": "value1" + "key2": "value2" + } + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `applicationInsightsConnectionString` | string | The connection string of the application insights. | +| `applicationInsightsInstrumentationKey` | string | The instrumentation key for the application insights. | +| `applicationInsightsName` | string | The name of the application insights. | +| `applicationInsightsResourceId` | string | The resource ID of the application insights. | +| `logAnalyticsWorkspaceName` | string | The name of the log analytics workspace. | +| `logAnalyticsWorkspaceResourceId` | string | The resource ID of the loganalytics workspace. | +| `resourceGroupName` | string | The resource group the operational-insights monitoring was deployed into. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/ptn/azd/insights-dashboard:0.1.0` | Remote reference | +| `br/public:avm/res/operational-insights/workspace:0.7.0` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/ptn/azd/monitoring/main.bicep b/avm/ptn/azd/monitoring/main.bicep new file mode 100644 index 0000000000..6097ac2df3 --- /dev/null +++ b/avm/ptn/azd/monitoring/main.bicep @@ -0,0 +1,102 @@ +metadata name = 'Azd Azure Monitoring' +metadata description = '''Creates an Application Insights instance and a Log Analytics workspace. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The resource operational insights workspaces name.') +param logAnalyticsName string + +@description('Required. The resource insights components name.') +param applicationInsightsName string + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. The resource portal dashboards name.') +param applicationInsightsDashboardName string = '' + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +@metadata({ + example: ''' + { + "key1": "value1" + "key2": "value2" + } + ''' +}) +param tags object? + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.azd-monitoring.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +module logAnalytics 'br/public:avm/res/operational-insights/workspace:0.7.0' = { + name: 'loganalytics' + params: { + name: logAnalyticsName + location: location + tags: tags + dataRetention: 30 + enableTelemetry: enableTelemetry + } +} + +module applicationInsights 'br/public:avm/ptn/azd/insights-dashboard:0.1.0' = { + name: 'applicationinsights' + params: { + logAnalyticsWorkspaceResourceId: logAnalytics.outputs.resourceId + name: applicationInsightsName + location: location + tags: tags + dashboardName: applicationInsightsDashboardName + enableTelemetry: enableTelemetry + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The resource group the operational-insights monitoring was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The connection string of the application insights.') +output applicationInsightsConnectionString string = applicationInsights.outputs.applicationInsightsConnectionString + +@description('The resource ID of the application insights.') +output applicationInsightsResourceId string = applicationInsights.outputs.applicationInsightsResourceId + +@description('The instrumentation key for the application insights.') +output applicationInsightsInstrumentationKey string = applicationInsights.outputs.applicationInsightsInstrumentationKey + +@description('The name of the application insights.') +output applicationInsightsName string = applicationInsights.outputs.applicationInsightsName + +@description('The resource ID of the loganalytics workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalytics.outputs.resourceId + +@description('The name of the log analytics workspace.') +output logAnalyticsWorkspaceName string = logAnalytics.outputs.name diff --git a/avm/ptn/azd/monitoring/main.json b/avm/ptn/azd/monitoring/main.json new file mode 100644 index 0000000000..9ed61ab0a1 --- /dev/null +++ b/avm/ptn/azd/monitoring/main.json @@ -0,0 +1,4604 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "2617595057203001759" + }, + "name": "Azd Azure Monitoring", + "description": "Creates an Application Insights instance and a Log Analytics workspace.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsName": { + "type": "string", + "metadata": { + "description": "Required. The resource operational insights workspaces name." + } + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "applicationInsightsDashboardName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource portal dashboards name." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-monitoring.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalytics": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "loganalytics", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('logAnalyticsName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "dataRetention": { + "value": 30 + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "11627784326487264389" + }, + "name": "Log Analytics Workspaces", + "description": "This module deploys a Log Analytics Workspace.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "useThisWorkspace": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Instead of using an external reference, use the deployed instance as the target for its diagnostic settings. If set to `true`, the `workspaceResourceId` property is ignored." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "skuName": { + "type": "string", + "defaultValue": "PerGB2018", + "allowedValues": [ + "CapacityReservation", + "Free", + "LACluster", + "PerGB2018", + "PerNode", + "Premium", + "Standalone", + "Standard" + ], + "metadata": { + "description": "Optional. The name of the SKU." + } + }, + "skuCapacityReservationLevel": { + "type": "int", + "defaultValue": 100, + "minValue": 100, + "maxValue": 5000, + "metadata": { + "description": "Optional. The capacity reservation level in GB for this workspace, when CapacityReservation sku is selected. Must be in increments of 100 between 100 and 5000." + } + }, + "storageInsightsConfigs": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of storage accounts to be read by the workspace." + } + }, + "linkedServices": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of services to be linked." + } + }, + "linkedStorageAccounts": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Conditional. List of Storage Accounts to be linked. Required if 'forceCmkForQuery' is set to 'true' and 'savedSearches' is not empty." + } + }, + "savedSearches": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Kusto Query Language searches to save." + } + }, + "dataExports": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW data export instances to be deployed." + } + }, + "dataSources": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW data sources to configure." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. LAW custom tables to be deployed." + } + }, + "gallerySolutions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of gallerySolutions to be created in the log analytics workspace." + } + }, + "dataRetention": { + "type": "int", + "defaultValue": 365, + "minValue": 0, + "maxValue": 730, + "metadata": { + "description": "Optional. Number of days data will be retained for." + } + }, + "dailyQuotaGb": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "metadata": { + "description": "Optional. The workspace daily quota for ingestion." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics ingestion." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Log Analytics query." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." + } + }, + "useResourcePermissions": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Set to 'true' to use resource or workspace permissions and 'false' (or leave empty) to require workspace permissions." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "forceCmkForQuery": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether customer managed storage is mandatory for query management." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Security Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'fb1c8493-542b-48eb-b624-b4c8fea62acd')]", + "Security Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '39bc4728-0917-49c7-9d2c-d95423bc2eb4')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.operationalinsights-workspace.{0}.{1}', replace('0.7.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalyticsWorkspace": { + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "features": { + "searchVersion": 1, + "enableLogAccessUsingOnlyResourcePermissions": "[parameters('useResourcePermissions')]" + }, + "sku": { + "name": "[parameters('skuName')]", + "capacityReservationLevel": "[if(equals(parameters('skuName'), 'CapacityReservation'), parameters('skuCapacityReservationLevel'), null())]" + }, + "retentionInDays": "[parameters('dataRetention')]", + "workspaceCapping": { + "dailyQuotaGb": "[parameters('dailyQuotaGb')]" + }, + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "forceCmkForQuery": "[parameters('forceCmkForQuery')]" + }, + "identity": "[variables('identity')]" + }, + "logAnalyticsWorkspace_diagnosticSettings": { + "copy": { + "name": "logAnalyticsWorkspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[if(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'useThisWorkspace'), false()), resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId'))]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_roleAssignments": { + "copy": { + "name": "logAnalyticsWorkspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_storageInsightConfigs": { + "copy": { + "name": "logAnalyticsWorkspace_storageInsightConfigs", + "count": "[length(parameters('storageInsightsConfigs'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-StorageInsightsConfig-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "containers": { + "value": "[tryGet(parameters('storageInsightsConfigs')[copyIndex()], 'containers')]" + }, + "tables": { + "value": "[tryGet(parameters('storageInsightsConfigs')[copyIndex()], 'tables')]" + }, + "storageAccountResourceId": { + "value": "[parameters('storageInsightsConfigs')[copyIndex()].storageAccountResourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "1745671120474305926" + }, + "name": "Log Analytics Workspace Storage Insight Configs", + "description": "This module deploys a Log Analytics Workspace Storage Insight Config.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-stinsconfig', last(split(parameters('storageAccountResourceId'), '/')))]", + "metadata": { + "description": "Optional. The name of the storage insights config." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. The Azure Resource Manager ID of the storage account resource." + } + }, + "containers": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The names of the blob containers that the workspace should read." + } + }, + "tables": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The names of the Azure tables that the workspace should read." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + } + }, + "resources": { + "storageAccount": { + "existing": true, + "type": "Microsoft.Storage/storageAccounts", + "apiVersion": "2022-09-01", + "name": "[last(split(parameters('storageAccountResourceId'), '/'))]" + }, + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "storageinsightconfig": { + "type": "Microsoft.OperationalInsights/workspaces/storageInsightConfigs", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "containers": "[parameters('containers')]", + "tables": "[parameters('tables')]", + "storageAccount": { + "id": "[parameters('storageAccountResourceId')]", + "key": "[listKeys(resourceId('Microsoft.Storage/storageAccounts', last(split(parameters('storageAccountResourceId'), '/'))), '2022-09-01').keys[0].value]" + } + }, + "dependsOn": [ + "storageAccount", + "workspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed storage insights configuration." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/storageInsightConfigs', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the storage insight configuration is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the storage insights configuration." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedServices": { + "copy": { + "name": "logAnalyticsWorkspace_linkedServices", + "count": "[length(parameters('linkedServices'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-LinkedService-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('linkedServices')[copyIndex()].name]" + }, + "resourceId": { + "value": "[tryGet(parameters('linkedServices')[copyIndex()], 'resourceId')]" + }, + "writeAccessResourceId": { + "value": "[tryGet(parameters('linkedServices')[copyIndex()], 'writeAccessResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "12032441371027552374" + }, + "name": "Log Analytics Workspace Linked Services", + "description": "This module deploys a Log Analytics Workspace Linked Service.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Required. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + }, + "writeAccessResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require write access." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "linkedService": { + "type": "Microsoft.OperationalInsights/workspaces/linkedServices", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "resourceId": "[parameters('resourceId')]", + "writeAccessResourceId": "[if(empty(parameters('writeAccessResourceId')), null(), parameters('writeAccessResourceId'))]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked service." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked service." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedServices', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked service is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_linkedStorageAccounts": { + "copy": { + "name": "logAnalyticsWorkspace_linkedStorageAccounts", + "count": "[length(parameters('linkedStorageAccounts'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-LinkedStorageAccount-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('linkedStorageAccounts')[copyIndex()].name]" + }, + "resourceId": { + "value": "[parameters('linkedStorageAccounts')[copyIndex()].resourceId]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "12623216644328477682" + }, + "name": "Log Analytics Workspace Linked Storage Accounts", + "description": "This module deploys a Log Analytics Workspace Linked Storage Account.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "allowedValues": [ + "Query", + "Alerts", + "CustomLogs", + "AzureWatson" + ], + "metadata": { + "description": "Required. Name of the link." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the resource that will be linked to the workspace. This should be used for linking resources which require read access." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/linkedStorageAccounts", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "storageAccountIds": [ + "[parameters('resourceId')]" + ] + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed linked storage account." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed linked storage account." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/linkedStorageAccounts', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the linked storage account is deployed." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_savedSearches": { + "copy": { + "name": "logAnalyticsWorkspace_savedSearches", + "count": "[length(parameters('savedSearches'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-SavedSearch-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[format('{0}{1}', parameters('savedSearches')[copyIndex()].name, uniqueString(deployment().name))]" + }, + "etag": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'etag')]" + }, + "displayName": { + "value": "[parameters('savedSearches')[copyIndex()].displayName]" + }, + "category": { + "value": "[parameters('savedSearches')[copyIndex()].category]" + }, + "query": { + "value": "[parameters('savedSearches')[copyIndex()].query]" + }, + "functionAlias": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'functionAlias')]" + }, + "functionParameters": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'functionParameters')]" + }, + "version": { + "value": "[tryGet(parameters('savedSearches')[copyIndex()], 'version')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "7683333179440464721" + }, + "name": "Log Analytics Workspace Saved Searches", + "description": "This module deploys a Log Analytics Workspace Saved Search.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the saved search." + } + }, + "displayName": { + "type": "string", + "metadata": { + "description": "Required. Display name for the search." + } + }, + "category": { + "type": "string", + "metadata": { + "description": "Required. Query category." + } + }, + "query": { + "type": "string", + "metadata": { + "description": "Required. Kusto Query to be stored." + } + }, + "tags": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + }, + "functionAlias": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The function alias if query serves as a function." + } + }, + "functionParameters": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The optional function parameters if query serves as a function. Value should be in the following format: \"param-name1:type1 = default_value1, param-name2:type2 = default_value2\". For more examples and proper syntax please refer to /azure/kusto/query/functions/user-defined-functions." + } + }, + "version": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The version number of the query language." + } + }, + "etag": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. The ETag of the saved search. To override an existing saved search, use \"*\" or specify the current Etag." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "savedSearch": { + "type": "Microsoft.OperationalInsights/workspaces/savedSearches", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "properties": { + "etag": "[parameters('etag')]", + "tags": "[coalesce(parameters('tags'), createArray())]", + "displayName": "[parameters('displayName')]", + "category": "[parameters('category')]", + "query": "[parameters('query')]", + "functionAlias": "[parameters('functionAlias')]", + "functionParameters": "[parameters('functionParameters')]", + "version": "[parameters('version')]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed saved search." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/savedSearches', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the saved search is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed saved search." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace", + "logAnalyticsWorkspace_linkedStorageAccounts" + ] + }, + "logAnalyticsWorkspace_dataExports": { + "copy": { + "name": "logAnalyticsWorkspace_dataExports", + "count": "[length(parameters('dataExports'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-DataExport-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('dataExports')[copyIndex()].name]" + }, + "destination": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'destination')]" + }, + "enable": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'enable')]" + }, + "tableNames": { + "value": "[tryGet(parameters('dataExports')[copyIndex()], 'tableNames')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5765609820817623497" + }, + "name": "Log Analytics Workspace Data Exports", + "description": "This module deploys a Log Analytics Workspace Data Export.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "minLength": 4, + "maxLength": 63, + "metadata": { + "description": "Required. The data export rule name." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "destination": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Destination properties." + } + }, + "enable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Active when enabled." + } + }, + "tableNames": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. An array of tables to export, for example: ['Heartbeat', 'SecurityEvent']." + } + } + }, + "resources": [ + { + "type": "Microsoft.OperationalInsights/workspaces/dataExports", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "destination": "[parameters('destination')]", + "enable": "[parameters('enable')]", + "tableNames": "[parameters('tableNames')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the data export." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the data export." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataExports', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the data export was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_dataSources": { + "copy": { + "name": "logAnalyticsWorkspace_dataSources", + "count": "[length(parameters('dataSources'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-DataSource-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('dataSources')[copyIndex()].name]" + }, + "kind": { + "value": "[parameters('dataSources')[copyIndex()].kind]" + }, + "linkedResourceId": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'linkedResourceId')]" + }, + "eventLogName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'eventLogName')]" + }, + "eventTypes": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'eventTypes')]" + }, + "objectName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'objectName')]" + }, + "instanceName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'instanceName')]" + }, + "intervalSeconds": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'intervalSeconds')]" + }, + "counterName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'counterName')]" + }, + "state": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'state')]" + }, + "syslogName": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'syslogName')]" + }, + "syslogSeverities": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'syslogSeverities')]" + }, + "performanceCounters": { + "value": "[tryGet(parameters('dataSources')[copyIndex()], 'performanceCounters')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "13460038983765020046" + }, + "name": "Log Analytics Workspace Datasources", + "description": "This module deploys a Log Analytics Workspace Data Source.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Log Analytics workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution." + } + }, + "kind": { + "type": "string", + "defaultValue": "AzureActivityLog", + "allowedValues": [ + "AzureActivityLog", + "WindowsEvent", + "WindowsPerformanceCounter", + "IISLogs", + "LinuxSyslog", + "LinuxSyslogCollection", + "LinuxPerformanceObject", + "LinuxPerformanceCollection" + ], + "metadata": { + "description": "Required. The kind of the DataSource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to configure in the resource." + } + }, + "linkedResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Resource ID of the resource to be linked." + } + }, + "eventLogName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Windows event log name to configure when kind is WindowsEvent." + } + }, + "eventTypes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Windows event types to configure when kind is WindowsEvent." + } + }, + "objectName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of the object to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "instanceName": { + "type": "string", + "defaultValue": "*", + "metadata": { + "description": "Optional. Name of the instance to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "intervalSeconds": { + "type": "int", + "defaultValue": 60, + "metadata": { + "description": "Optional. Interval in seconds to configure when kind is WindowsPerformanceCounter or LinuxPerformanceObject." + } + }, + "performanceCounters": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of counters to configure when the kind is LinuxPerformanceObject." + } + }, + "counterName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Counter name to configure when kind is WindowsPerformanceCounter." + } + }, + "state": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. State to configure when kind is IISLogs or LinuxSyslogCollection or LinuxPerformanceCollection." + } + }, + "syslogName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. System log to configure when kind is LinuxSyslog." + } + }, + "syslogSeverities": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Severities to configure when kind is LinuxSyslog." + } + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('logAnalyticsWorkspaceName')]" + }, + "dataSource": { + "type": "Microsoft.OperationalInsights/workspaces/dataSources", + "apiVersion": "2020-08-01", + "name": "[format('{0}/{1}', parameters('logAnalyticsWorkspaceName'), parameters('name'))]", + "kind": "[parameters('kind')]", + "tags": "[parameters('tags')]", + "properties": { + "linkedResourceId": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'AzureActivityLog')), parameters('linkedResourceId'), null())]", + "eventLogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventLogName'), null())]", + "eventTypes": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsEvent')), parameters('eventTypes'), null())]", + "objectName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('objectName'), null())]", + "instanceName": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('instanceName'), null())]", + "intervalSeconds": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'WindowsPerformanceCounter'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('intervalSeconds'), null())]", + "counterName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'WindowsPerformanceCounter')), parameters('counterName'), null())]", + "state": "[if(and(not(empty(parameters('kind'))), or(or(equals(parameters('kind'), 'IISLogs'), equals(parameters('kind'), 'LinuxSyslogCollection')), equals(parameters('kind'), 'LinuxPerformanceCollection'))), parameters('state'), null())]", + "syslogName": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxSyslog')), parameters('syslogName'), null())]", + "syslogSeverities": "[if(and(not(empty(parameters('kind'))), or(equals(parameters('kind'), 'LinuxSyslog'), equals(parameters('kind'), 'LinuxPerformanceObject'))), parameters('syslogSeverities'), null())]", + "performanceCounters": "[if(and(not(empty(parameters('kind'))), equals(parameters('kind'), 'LinuxPerformanceObject')), parameters('performanceCounters'), null())]" + }, + "dependsOn": [ + "workspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed data source." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/dataSources', parameters('logAnalyticsWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the data source is deployed." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed data source." + }, + "value": "[parameters('name')]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_tables": { + "copy": { + "name": "logAnalyticsWorkspace_tables", + "count": "[length(parameters('tables'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-Table-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "workspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('tables')[copyIndex()].name]" + }, + "plan": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'plan')]" + }, + "schema": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'schema')]" + }, + "retentionInDays": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'retentionInDays')]" + }, + "totalRetentionInDays": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'totalRetentionInDays')]" + }, + "restoredLogs": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'restoredLogs')]" + }, + "searchResults": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'searchResults')]" + }, + "roleAssignments": { + "value": "[tryGet(parameters('tables')[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "10380077652898392916" + }, + "name": "Log Analytics Workspace Tables", + "description": "This module deploys a Log Analytics Workspace Table.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the table." + } + }, + "workspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent workspaces. Required if the template is used in a standalone deployment." + } + }, + "plan": { + "type": "string", + "defaultValue": "Analytics", + "allowedValues": [ + "Basic", + "Analytics" + ], + "metadata": { + "description": "Optional. Instruct the system how to handle and charge the logs ingested to this table." + } + }, + "restoredLogs": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Restore parameters." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "maxValue": 730, + "metadata": { + "description": "Optional. The table retention in days, between 4 and 730. Setting this property to -1 will default to the workspace retention." + } + }, + "schema": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Table's schema." + } + }, + "searchResults": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Parameters of the search job that initiated this table." + } + }, + "totalRetentionInDays": { + "type": "int", + "defaultValue": -1, + "minValue": -1, + "maxValue": 2555, + "metadata": { + "description": "Optional. The table total retention in days, between 4 and 2555. Setting this property to -1 will default to table retention." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Log Analytics Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293')]", + "Log Analytics Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]", + "Monitoring Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "workspace": { + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('workspaceName')]" + }, + "table": { + "type": "Microsoft.OperationalInsights/workspaces/tables", + "apiVersion": "2022-10-01", + "name": "[format('{0}/{1}', parameters('workspaceName'), parameters('name'))]", + "properties": { + "plan": "[parameters('plan')]", + "restoredLogs": "[parameters('restoredLogs')]", + "retentionInDays": "[parameters('retentionInDays')]", + "schema": "[parameters('schema')]", + "searchResults": "[parameters('searchResults')]", + "totalRetentionInDays": "[parameters('totalRetentionInDays')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "table_roleAssignments": { + "copy": { + "name": "table_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.OperationalInsights/workspaces/{0}/tables/{1}', parameters('workspaceName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "table" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the table." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the table." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces/tables', parameters('workspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the table was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + }, + "logAnalyticsWorkspace_solutions": { + "copy": { + "name": "logAnalyticsWorkspace_solutions", + "count": "[length(parameters('gallerySolutions'))]" + }, + "condition": "[not(empty(parameters('gallerySolutions')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-LAW-Solution-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('gallerySolutions')[copyIndex()].name]" + }, + "location": { + "value": "[parameters('location')]" + }, + "logAnalyticsWorkspaceName": { + "value": "[parameters('name')]" + }, + "product": { + "value": "[tryGet(parameters('gallerySolutions')[copyIndex()], 'product')]" + }, + "publisher": { + "value": "[tryGet(parameters('gallerySolutions')[copyIndex()], 'publisher')]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(parameters('gallerySolutions')[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "18444780972506374592" + }, + "name": "Operations Management Solutions", + "description": "This module deploys an Operations Management Solution.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the solution. For Microsoft published gallery solution the target solution resource name will be composed as `{name}({logAnalyticsWorkspaceName})`." + } + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. Name of the Log Analytics workspace where the solution will be deployed/enabled." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "product": { + "type": "string", + "defaultValue": "OMSGallery", + "metadata": { + "description": "Optional. The product of the deployed solution. For Microsoft published gallery solution it should be `OMSGallery` and the target solution resource product will be composed as `OMSGallery/{name}`. For third party solution, it can be anything. This is case sensitive." + } + }, + "publisher": { + "type": "string", + "defaultValue": "Microsoft", + "metadata": { + "description": "Optional. The publisher name of the deployed solution. For Microsoft published gallery solution, it is `Microsoft`." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "solutionName": "[if(equals(parameters('publisher'), 'Microsoft'), format('{0}({1})', parameters('name'), parameters('logAnalyticsWorkspaceName')), parameters('name'))]", + "solutionProduct": "[if(equals(parameters('publisher'), 'Microsoft'), format('OMSGallery/{0}', parameters('name')), parameters('product'))]" + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.operationsmanagement-solution.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.OperationsManagement/solutions", + "apiVersion": "2015-11-01-preview", + "name": "[variables('solutionName')]", + "location": "[parameters('location')]", + "properties": { + "workspaceResourceId": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsWorkspaceName'))]" + }, + "plan": { + "name": "[variables('solutionName')]", + "promotionCode": "", + "product": "[variables('solutionProduct')]", + "publisher": "[parameters('publisher')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed solution." + }, + "value": "[variables('solutionName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed solution." + }, + "value": "[resourceId('Microsoft.OperationsManagement/solutions', variables('solutionName'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group where the solution is deployed." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference(resourceId('Microsoft.OperationsManagement/solutions', variables('solutionName')), '2015-11-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "logAnalyticsWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the deployed log analytics workspace." + }, + "value": "[resourceId('Microsoft.OperationalInsights/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group of the deployed log analytics workspace." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the deployed log analytics workspace." + }, + "value": "[parameters('name')]" + }, + "logAnalyticsWorkspaceId": { + "type": "string", + "metadata": { + "description": "The ID associated with the workspace." + }, + "value": "[reference('logAnalyticsWorkspace').customerId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('logAnalyticsWorkspace', '2022-10-01', 'full').location]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('logAnalyticsWorkspace', '2022-10-01', 'full'), 'identity'), 'principalId'), '')]" + } + } + } + } + }, + "applicationInsights": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "applicationinsights", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "logAnalyticsWorkspaceResourceId": { + "value": "[reference('logAnalytics').outputs.resourceId.value]" + }, + "name": { + "value": "[parameters('applicationInsightsName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "dashboardName": { + "value": "[parameters('applicationInsightsDashboardName')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "17156187352453961206" + }, + "name": "Application Insights Components", + "description": "Creates an Application Insights instance based on an existing Log Analytics workspace.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "dashboardName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource portal dashboards name." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the loganalytics workspace." + } + }, + "kind": { + "type": "string", + "defaultValue": "web", + "metadata": { + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-insightsdashboard.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "applicationInsights": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-appinsights', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "kind": { + "value": "[parameters('kind')]" + }, + "applicationType": { + "value": "[parameters('applicationType')]" + }, + "workspaceResourceId": { + "value": "[parameters('logAnalyticsWorkspaceResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "10653241142071426932" + }, + "name": "Application Insights", + "description": "This component deploys an Application Insights instance.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Application Insights." + } + }, + "applicationType": { + "type": "string", + "defaultValue": "web", + "allowedValues": [ + "web", + "other" + ], + "metadata": { + "description": "Optional. Application type." + } + }, + "workspaceResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the log analytics workspace which the data will be ingested to. This property is required to create an application with this API version. Applications from older versions will not have this property." + } + }, + "disableIpMasking": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Disable IP masking. Default value is set to true." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Disable Non-AAD based Auth. Default value is set to false." + } + }, + "forceCustomerStorageForProfiler": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Force users to create their own storage account for profiler and debugger." + } + }, + "linkedStorageAccountResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Linked storage account resource ID." + } + }, + "publicNetworkAccessForIngestion": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights ingestion. - Enabled or Disabled." + } + }, + "publicNetworkAccessForQuery": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. The network access type for accessing Application Insights query. - Enabled or Disabled." + } + }, + "retentionInDays": { + "type": "int", + "defaultValue": 365, + "allowedValues": [ + 30, + 60, + 90, + 120, + 180, + 270, + 365, + 550, + 730 + ], + "metadata": { + "description": "Optional. Retention period in days." + } + }, + "samplingPercentage": { + "type": "int", + "defaultValue": 100, + "minValue": 0, + "maxValue": 100, + "metadata": { + "description": "Optional. Percentage of the data produced by the application being monitored that is being sampled for Application Insights telemetry." + } + }, + "kind": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The kind of application that this component refers to, used to customize UI. This value is a freeform string, values should typically be one of the following: web, ios, other, store, java, phone." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]", + "Monitoring Metrics Publisher": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb')]", + "Application Insights Component Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ae349356-3a1b-4a5e-921d-050484c6347e')]", + "Application Insights Snapshot Debugger": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '08954f03-6346-4c2e-81c0-ec3a5cfae23b')]", + "Monitoring Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.insights-component.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "appInsights": { + "type": "Microsoft.Insights/components", + "apiVersion": "2020-02-02", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "kind": "[parameters('kind')]", + "properties": { + "Application_Type": "[parameters('applicationType')]", + "DisableIpMasking": "[parameters('disableIpMasking')]", + "DisableLocalAuth": "[parameters('disableLocalAuth')]", + "ForceCustomerStorageForProfiler": "[parameters('forceCustomerStorageForProfiler')]", + "WorkspaceResourceId": "[parameters('workspaceResourceId')]", + "publicNetworkAccessForIngestion": "[parameters('publicNetworkAccessForIngestion')]", + "publicNetworkAccessForQuery": "[parameters('publicNetworkAccessForQuery')]", + "RetentionInDays": "[parameters('retentionInDays')]", + "SamplingPercentage": "[parameters('samplingPercentage')]" + } + }, + "appInsights_roleAssignments": { + "copy": { + "name": "appInsights_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Insights/components', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "appInsights_diagnosticSettings": { + "copy": { + "name": "appInsights_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Insights/components/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "appInsights" + ] + }, + "linkedStorageAccount": { + "condition": "[not(empty(parameters('linkedStorageAccountResourceId')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-appInsights-linkedStorageAccount', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "appInsightsName": { + "value": "[parameters('name')]" + }, + "storageAccountResourceId": { + "value": "[parameters('linkedStorageAccountResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "216781367921725873" + }, + "name": "Application Insights Linked Storage Account", + "description": "This component deploys an Application Insights Linked Storage Account.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "appInsightsName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Application Insights instance. Required if the template is used in a standalone deployment." + } + }, + "storageAccountResourceId": { + "type": "string", + "metadata": { + "description": "Required. Linked storage account resource ID." + } + } + }, + "resources": [ + { + "type": "microsoft.insights/components/linkedStorageAccounts", + "apiVersion": "2020-03-01-preview", + "name": "[format('{0}/{1}', parameters('appInsightsName'), 'ServiceProfiler')]", + "properties": { + "linkedStorageAccount": "[parameters('storageAccountResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Linked Storage Account." + }, + "value": "ServiceProfiler" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Linked Storage Account." + }, + "value": "[resourceId('microsoft.insights/components/linkedStorageAccounts', parameters('appInsightsName'), 'ServiceProfiler')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "appInsights" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the application insights component." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights component." + }, + "value": "[resourceId('Microsoft.Insights/components', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights component was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationId": { + "type": "string", + "metadata": { + "description": "The application ID of the application insights component." + }, + "value": "[reference('appInsights').AppId]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('appInsights', '2020-02-02', 'full').location]" + }, + "instrumentationKey": { + "type": "string", + "metadata": { + "description": "Application Insights Instrumentation key. A read-only value that applications can use to identify the destination for all telemetry sent to Azure Application Insights. This value will be supplied upon construction of each new Application Insights component." + }, + "value": "[reference('appInsights').InstrumentationKey]" + }, + "connectionString": { + "type": "string", + "metadata": { + "description": "Application Insights Connection String." + }, + "value": "[reference('appInsights').ConnectionString]" + } + } + } + } + }, + "applicationInsightsDashboard": { + "condition": "[not(empty(parameters('dashboardName')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "application-insights-dashboard", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('dashboardName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "applicationInsightsName": { + "value": "[reference('applicationInsights').outputs.name.value]" + }, + "applicationInsightsResourceId": { + "value": "[reference('applicationInsights').outputs.resourceId.value]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "9856731218551847403" + }, + "name": "Azure Portal Dashboard", + "description": "Creates a dashboard for an Application Insights instance.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The portal dashboard name." + } + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components name." + } + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource insights components ID." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + } + }, + "resources": { + "dashboard": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "dashboard-deployment", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "lenses": { + "value": [ + { + "order": 0, + "parts": [ + { + "position": { + "x": 0, + "y": 0, + "colSpan": 2, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "id", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AspNetOverviewPinnedPart", + "asset": { + "idInputName": "id", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "overview" + } + }, + { + "position": { + "x": 2, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/ProactiveDetectionAsyncPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "ProactiveDetection" + } + }, + { + "position": { + "x": 3, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + } + ], + "type": "Extension/AppInsightsExtension/PartType/QuickPulseButtonSmallPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 4, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-04T01:20:33.345Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AvailabilityNavButtonPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 5, + "y": 0, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-08T18:47:35.237Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "ConfigurationId", + "value": "78ce933e-e864-4b05-a27b-71fd55a6afad" + } + ], + "type": "Extension/AppInsightsExtension/PartType/AppMapButtonPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 0, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Usage", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 3, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "endTime": null, + "createdTime": "2018-05-04T01:22:35.782Z", + "isInitialTime": true, + "grain": 1, + "useDashboardTimeRange": false + } + } + ], + "type": "Extension/AppInsightsExtension/PartType/UsageUsersOverviewPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + } + } + }, + { + "position": { + "x": 4, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Reliability", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 7, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "DataModel", + "value": { + "version": "1.0.0", + "timeContext": { + "durationMs": 86400000, + "createdTime": "2018-05-04T23:42:40.072Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + "isOptional": true + }, + { + "name": "ConfigurationId", + "value": "8a02f7bf-ac0f-40e1-afe9-f0e72cfee77f", + "isOptional": true + } + ], + "type": "Extension/AppInsightsExtension/PartType/CuratedBladeFailuresPinnedPart", + "isAdapter": true, + "asset": { + "idInputName": "ResourceId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "failures" + } + }, + { + "position": { + "x": 8, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Responsiveness\r\n", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 11, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ResourceId", + "value": "[parameters('applicationInsightsResourceId')]" + }, + { + "name": "DataModel", + "value": { + "version": "1.0.0", + "timeContext": { + "durationMs": 86400000, + "createdTime": "2018-05-04T23:43:37.804Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + "isOptional": true + }, + { + "name": "ConfigurationId", + "value": "2a8ede4f-2bee-4b9c-aed9-2db0e8a01865", + "isOptional": true + } + ], + "type": "Extension/AppInsightsExtension/PartType/CuratedBladePerformancePinnedPart", + "isAdapter": true, + "asset": { + "idInputName": "ResourceId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "performance" + } + }, + { + "position": { + "x": 12, + "y": 1, + "colSpan": 3, + "rowSpan": 1 + }, + "metadata": { + "inputs": [], + "type": "Extension/HubsExtension/PartType/MarkdownPart", + "settings": { + "content": { + "settings": { + "content": "# Browser", + "title": "", + "subtitle": "" + } + } + } + } + }, + { + "position": { + "x": 15, + "y": 1, + "colSpan": 1, + "rowSpan": 1 + }, + "metadata": { + "inputs": [ + { + "name": "ComponentId", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "MetricsExplorerJsonDefinitionId", + "value": "BrowserPerformanceTimelineMetrics" + }, + { + "name": "TimeContext", + "value": { + "durationMs": 86400000, + "createdTime": "2018-05-08T12:16:27.534Z", + "isInitialTime": false, + "grain": 1, + "useDashboardTimeRange": false + } + }, + { + "name": "CurrentFilter", + "value": { + "eventTypes": [ + 4, + 1, + 3, + 5, + 2, + 6, + 13 + ], + "typeFacets": {}, + "isPermissive": false + } + }, + { + "name": "id", + "value": { + "Name": "[parameters('applicationInsightsName')]", + "SubscriptionId": "[subscription().subscriptionId]", + "ResourceGroup": "[resourceGroup().name]" + } + }, + { + "name": "Version", + "value": "1.0" + } + ], + "type": "Extension/AppInsightsExtension/PartType/MetricsExplorerBladePinnedPart", + "asset": { + "idInputName": "ComponentId", + "type": "ApplicationInsights" + }, + "defaultMenuItemId": "browser" + } + }, + { + "position": { + "x": 0, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "sessions/count", + "aggregationType": 5, + "namespace": "microsoft.insights/components/kusto", + "metricVisualization": { + "displayName": "Sessions", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "users/count", + "aggregationType": 5, + "namespace": "microsoft.insights/components/kusto", + "metricVisualization": { + "displayName": "Users", + "color": "#7E58FF" + } + } + ], + "title": "Unique sessions and users", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "segmentationUsers" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "requests/failed", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Failed requests", + "color": "#EC008C" + } + } + ], + "title": "Failed requests", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "failures" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "requests/duration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Server response time", + "color": "#00BCF2" + } + } + ], + "title": "Server response time", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "performance" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 12, + "y": 2, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/networkDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Page load network connect time", + "color": "#7E58FF" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/processingDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Client processing time", + "color": "#44F1C8" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/sendDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Send request time", + "color": "#EB9371" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "browserTimings/receiveDuration", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Receiving response time", + "color": "#0672F1" + } + } + ], + "title": "Average page load time breakdown", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 0, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "availabilityResults/availabilityPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Availability", + "color": "#47BDF5" + } + } + ], + "title": "Average availability", + "visualization": { + "chartType": 3, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + }, + "openBladeOnClick": { + "openBlade": true, + "destinationBlade": { + "extensionName": "HubsExtension", + "bladeName": "ResourceMenuBlade", + "parameters": { + "id": "[parameters('applicationInsightsResourceId')]", + "menuid": "availability" + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "exceptions/server", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Server exceptions", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "dependencies/failed", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Dependency failures", + "color": "#7E58FF" + } + } + ], + "title": "Server exceptions and Dependency failures", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processorCpuPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Processor time", + "color": "#47BDF5" + } + }, + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processCpuPercentage", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Process CPU", + "color": "#7E58FF" + } + } + ], + "title": "Average processor and process CPU utilization", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 12, + "y": 5, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "exceptions/browser", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Browser exceptions", + "color": "#47BDF5" + } + } + ], + "title": "Browser exceptions", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 0, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "availabilityResults/count", + "aggregationType": 7, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Availability test results count", + "color": "#47BDF5" + } + } + ], + "title": "Availability test results count", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 4, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/processIOBytesPerSecond", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Process IO rate", + "color": "#47BDF5" + } + } + ], + "title": "Average process I/O rate", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + }, + { + "position": { + "x": 8, + "y": 8, + "colSpan": 4, + "rowSpan": 3 + }, + "metadata": { + "inputs": [ + { + "name": "options", + "value": { + "chart": { + "metrics": [ + { + "resourceMetadata": { + "id": "[parameters('applicationInsightsResourceId')]" + }, + "name": "performanceCounters/memoryAvailableBytes", + "aggregationType": 4, + "namespace": "microsoft.insights/components", + "metricVisualization": { + "displayName": "Available memory", + "color": "#47BDF5" + } + } + ], + "title": "Average available memory", + "visualization": { + "chartType": 2, + "legendVisualization": { + "isVisible": true, + "position": 2, + "hideSubtitle": false + }, + "axisVisualization": { + "x": { + "isVisible": true, + "axisType": 2 + }, + "y": { + "isVisible": true, + "axisType": 1 + } + } + } + } + } + }, + { + "name": "sharedTimeRange", + "isOptional": true + } + ], + "type": "Extension/HubsExtension/PartType/MonitorChartPart", + "settings": {} + } + } + ] + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "12676032921679464791" + }, + "name": "Portal Dashboards", + "description": "This module deploys a Portal Dashboard.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the dashboard to create." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "lenses": { + "type": "array", + "items": { + "type": "object" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. The dashboard lenses." + } + }, + "metadata": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The dashboard metadata." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.portal-dashboard.{0}.{1}', replace('0.1.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "dashboard": { + "type": "Microsoft.Portal/dashboards", + "apiVersion": "2020-09-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "lenses": "[parameters('lenses')]", + "metadata": "[parameters('metadata')]" + } + }, + "dashboard_roleAssignments": { + "copy": { + "name": "dashboard_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Portal/dashboards/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Portal/dashboards', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "dashboard" + ] + }, + "dashboard_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Portal/dashboards/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "dashboard" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[resourceId('Microsoft.Portal/dashboards', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the dashboard was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the dashboard." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the dashboard was deployed into." + }, + "value": "[reference('dashboard', '2020-09-01-preview', 'full').location]" + } + } + } + } + } + }, + "outputs": { + "dashboardResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[reference('dashboard').outputs.resourceId.value]" + }, + "dashboardName": { + "type": "string", + "metadata": { + "description": "The resource name of the dashboard." + }, + "value": "[reference('dashboard').outputs.name.value]" + } + } + } + }, + "dependsOn": [ + "applicationInsights" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights components were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "The name of the application insights." + }, + "value": "[reference('applicationInsights').outputs.name.value]" + }, + "dashboardName": { + "type": "string", + "metadata": { + "description": "The resource name of the dashboard." + }, + "value": "[if(not(empty(parameters('dashboardName'))), reference('applicationInsightsDashboard').outputs.dashboardName.value, '')]" + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights." + }, + "value": "[reference('applicationInsights').outputs.resourceId.value]" + }, + "dashboardResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the dashboard." + }, + "value": "[if(not(empty(parameters('dashboardName'))), reference('applicationInsightsDashboard').outputs.dashboardResourceId.value, '')]" + }, + "applicationInsightsConnectionString": { + "type": "string", + "metadata": { + "description": "The connection string of the application insights." + }, + "value": "[reference('applicationInsights').outputs.connectionString.value]" + }, + "applicationInsightsInstrumentationKey": { + "type": "string", + "metadata": { + "description": "The instrumentation key of the application insights." + }, + "value": "[reference('applicationInsights').outputs.instrumentationKey.value]" + } + } + } + }, + "dependsOn": [ + "logAnalytics" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the operational-insights monitoring was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "applicationInsightsConnectionString": { + "type": "string", + "metadata": { + "description": "The connection string of the application insights." + }, + "value": "[reference('applicationInsights').outputs.applicationInsightsConnectionString.value]" + }, + "applicationInsightsResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the application insights." + }, + "value": "[reference('applicationInsights').outputs.applicationInsightsResourceId.value]" + }, + "applicationInsightsInstrumentationKey": { + "type": "string", + "metadata": { + "description": "The instrumentation key for the application insights." + }, + "value": "[reference('applicationInsights').outputs.applicationInsightsInstrumentationKey.value]" + }, + "applicationInsightsName": { + "type": "string", + "metadata": { + "description": "The name of the application insights." + }, + "value": "[reference('applicationInsights').outputs.applicationInsightsName.value]" + }, + "logAnalyticsWorkspaceResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the loganalytics workspace." + }, + "value": "[reference('logAnalytics').outputs.resourceId.value]" + }, + "logAnalyticsWorkspaceName": { + "type": "string", + "metadata": { + "description": "The name of the log analytics workspace." + }, + "value": "[reference('logAnalytics').outputs.name.value]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/monitoring/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/monitoring/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..6a1efa2c23 --- /dev/null +++ b/avm/ptn/azd/monitoring/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,46 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-azd-monitoring-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'ammin' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + location: resourceLocation + logAnalyticsName: '${uniqueString(deployment().name, resourceLocation)}-test-log-analytics-${serviceShort}' + applicationInsightsName: '${uniqueString(deployment().name, resourceLocation)}-test-appinsights-${serviceShort}' + } +} diff --git a/avm/ptn/azd/monitoring/version.json b/avm/ptn/azd/monitoring/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/monitoring/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From f06337032c4595246698b33c0d63fbb1ef72b80d Mon Sep 17 00:00:00 2001 From: Salima-90 <103124614+Salima-90@users.noreply.github.com> Date: Fri, 11 Oct 2024 08:32:18 +0100 Subject: [PATCH 06/17] feat: separate backup snapshot policies netapps (#3403) ## Description - ANF backup and snapshot policies have been separated into their own modules ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.net-app.net-app-account](https://github.com/Salima-90/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml/badge.svg)](https://github.com/Salima-90/bicep-registry-modules/actions/workflows/avm.res.net-app.net-app-account.yml) | ## Type of Change - [x] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings --- .../net-app-account/backup-policies/README.md | 98 +++ .../backup-policies/main.bicep | 48 ++ .../net-app-account/backup-policies/main.json | 97 +++ .../net-app-account/capacity-pool/README.md | 10 + .../net-app-account/capacity-pool/main.bicep | 2 + .../net-app-account/capacity-pool/main.json | 669 +++++++++++++---- .../capacity-pool/volume/README.md | 56 +- .../capacity-pool/volume/main.bicep | 196 ++--- .../capacity-pool/volume/main.json | 659 +++++++++++++---- avm/res/net-app/net-app-account/main.json | 673 ++++++++++++++---- .../snapshot-policies/README.md | 205 ++++++ .../snapshot-policies/main.bicep | 113 +++ .../snapshot-policies/main.json | 204 ++++++ 13 files changed, 2499 insertions(+), 531 deletions(-) create mode 100644 avm/res/net-app/net-app-account/backup-policies/README.md create mode 100644 avm/res/net-app/net-app-account/backup-policies/main.bicep create mode 100644 avm/res/net-app/net-app-account/backup-policies/main.json create mode 100644 avm/res/net-app/net-app-account/snapshot-policies/README.md create mode 100644 avm/res/net-app/net-app-account/snapshot-policies/main.bicep create mode 100644 avm/res/net-app/net-app-account/snapshot-policies/main.json diff --git a/avm/res/net-app/net-app-account/backup-policies/README.md b/avm/res/net-app/net-app-account/backup-policies/README.md new file mode 100644 index 0000000000..6756951c04 --- /dev/null +++ b/avm/res/net-app/net-app-account/backup-policies/README.md @@ -0,0 +1,98 @@ +# Azure NetApp Files Backup Policy `[Microsoft.NetApp/netAppAccounts/backupPolicies]` + +This module deploys a Backup Policy for Azure NetApp File. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.NetApp/netAppAccounts/backupPolicies` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-03-01/netAppAccounts/backupPolicies) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backupPolicyName`](#parameter-backuppolicyname) | string | The name of the backup policy. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`netAppAccountName`](#parameter-netappaccountname) | string | The name of the parent NetApp account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`backupEnabled`](#parameter-backupenabled) | bool | Indicates whether the backup policy is enabled. | +| [`backupPolicyLocation`](#parameter-backuppolicylocation) | string | The location of the backup policy. Required if the template is used in a standalone deployment. | +| [`dailyBackupsToKeep`](#parameter-dailybackupstokeep) | int | The daily backups to keep. | +| [`monthlyBackupsToKeep`](#parameter-monthlybackupstokeep) | int | The monthly backups to keep. | +| [`weeklyBackupsToKeep`](#parameter-weeklybackupstokeep) | int | The weekly backups to keep. | + +### Parameter: `backupPolicyName` + +The name of the backup policy. + +- Required: No +- Type: string +- Default: `'backupPolicy'` + +### Parameter: `netAppAccountName` + +The name of the parent NetApp account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `backupEnabled` + +Indicates whether the backup policy is enabled. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `backupPolicyLocation` + +The location of the backup policy. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `dailyBackupsToKeep` + +The daily backups to keep. + +- Required: Yes +- Type: int + +### Parameter: `monthlyBackupsToKeep` + +The monthly backups to keep. + +- Required: Yes +- Type: int + +### Parameter: `weeklyBackupsToKeep` + +The weekly backups to keep. + +- Required: Yes +- Type: int + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the Backup Policy. | +| `resourceGroupName` | string | The name of the Resource Group the Backup Policy was created in. | +| `resourceId` | string | The resource IDs of the backup Policy created within volume. | diff --git a/avm/res/net-app/net-app-account/backup-policies/main.bicep b/avm/res/net-app/net-app-account/backup-policies/main.bicep new file mode 100644 index 0000000000..5a254eadfb --- /dev/null +++ b/avm/res/net-app/net-app-account/backup-policies/main.bicep @@ -0,0 +1,48 @@ +metadata name = 'Azure NetApp Files Backup Policy' +metadata description = 'This module deploys a Backup Policy for Azure NetApp File.' +metadata owner = 'Azure/module-maintainers' + +@description('Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment.') +param netAppAccountName string + +@description('Required. The name of the backup policy.') +param backupPolicyName string = 'backupPolicy' + +@description('Optional. The location of the backup policy. Required if the template is used in a standalone deployment.') +param backupPolicyLocation string + +@description('Optional. The daily backups to keep.') +param dailyBackupsToKeep int + +@description('Optional. The monthly backups to keep.') +param monthlyBackupsToKeep int + +@description('Optional. The weekly backups to keep.') +param weeklyBackupsToKeep int + +@description('Optional. Indicates whether the backup policy is enabled.') +param backupEnabled bool = false + +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-03-01' existing = { + name: netAppAccountName +} + +resource backupPolicies 'Microsoft.NetApp/netAppAccounts/backupPolicies@2024-03-01' = { + name: backupPolicyName + parent: netAppAccount + location: backupPolicyLocation + properties: { + dailyBackupsToKeep: dailyBackupsToKeep + enabled: backupEnabled + monthlyBackupsToKeep: monthlyBackupsToKeep + weeklyBackupsToKeep: weeklyBackupsToKeep + } +} +@description('The resource IDs of the backup Policy created within volume.') +output resourceId string = backupPolicies.id + +@description('The name of the Backup Policy.') +output name string = backupPolicies.name + +@description('The name of the Resource Group the Backup Policy was created in.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/res/net-app/net-app-account/backup-policies/main.json b/avm/res/net-app/net-app-account/backup-policies/main.json new file mode 100644 index 0000000000..315e53cdee --- /dev/null +++ b/avm/res/net-app/net-app-account/backup-policies/main.json @@ -0,0 +1,97 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "16399924782439066553" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Required. The name of the backup policy." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of the backup policy. Required if the template is used in a standalone deployment." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", + "location": "[parameters('backupPolicyLocation')]", + "properties": { + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "enabled": "[parameters('backupEnabled')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the backup Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), parameters('backupPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('backupPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Backup Policy was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/res/net-app/net-app-account/capacity-pool/README.md b/avm/res/net-app/net-app-account/capacity-pool/README.md index 4c95a9ca0b..888ae5f9ef 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/README.md +++ b/avm/res/net-app/net-app-account/capacity-pool/README.md @@ -7,6 +7,7 @@ This module deploys an Azure NetApp Files Capacity Pool. - [Resource Types](#Resource-Types) - [Parameters](#Parameters) - [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) ## Resource Types @@ -268,3 +269,12 @@ List of volumnes to create in the capacity pool. | `resourceGroupName` | string | The name of the Resource Group the Capacity Pool was created in. | | `resourceId` | string | The resource ID of the Capacity Pool. | | `volumeResourceId` | string | The resource IDs of the volume created in the capacity pool. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `res/net-app/net-app-account/backup-policies` | Local reference | +| `res/net-app/net-app-account/snapshot-policies` | Local reference | diff --git a/avm/res/net-app/net-app-account/capacity-pool/main.bicep b/avm/res/net-app/net-app-account/capacity-pool/main.bicep index 3fafb3a6cd..05ee747227 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/main.bicep +++ b/avm/res/net-app/net-app-account/capacity-pool/main.bicep @@ -157,6 +157,8 @@ module capacityPool_volumes 'volume/main.bicep' = [ useExistingSnapshot: volume.?useExistingSnapshot ?? false volumeResourceId: volume.?volumeResourceId ?? '' volumeType: volume.?volumeType ?? '' + backupVaultId: volume.?backupVaultId ?? '' + replicationEnabled: volume.?replicationEnabled ?? false } } ] diff --git a/avm/res/net-app/net-app-account/capacity-pool/main.json b/avm/res/net-app/net-app-account/capacity-pool/main.json index 34b2885f71..51024b061a 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/main.json +++ b/avm/res/net-app/net-app-account/capacity-pool/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8361786183534097212" + "version": "0.30.3.12046", + "templateHash": "5120059204101466005" }, "name": "Azure NetApp Files Capacity Pools", "description": "This module deploys an Azure NetApp Files Capacity Pool.", @@ -431,6 +431,12 @@ }, "volumeType": { "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'volumeType'), '')]" + }, + "backupVaultId": { + "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'backupVaultId'), '')]" + }, + "replicationEnabled": { + "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'replicationEnabled'), false())]" } }, "template": { @@ -440,8 +446,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18098024822158530053" + "version": "0.30.3.12046", + "templateHash": "3878108397799577614" }, "name": "Azure NetApp Files Capacity Pool Volumes", "description": "This module deploys an Azure NetApp Files Capacity Pool Volume.", @@ -604,88 +610,6 @@ "description": "Optional. The name of the backup policy." } }, - "backupPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup policy." - } - }, - "dailyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The daily backups to keep." - } - }, - "monthlyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The monthly backups to keep." - } - }, - "weeklyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The weekly backups to keep." - } - }, - "backupVaultName": { - "type": "string", - "defaultValue": "vault", - "metadata": { - "description": "Optional. The name of the backup vault." - } - }, - "backupVaultLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup vault." - } - }, - "backupName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "backupLabel": { - "type": "string", - "metadata": { - "description": "Optional. The label of the backup." - } - }, - "useExistingSnapshot": { - "type": "bool", - "metadata": { - "description": "Optional. Indicates whether to use an existing snapshot." - } - }, - "snapshotName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "snapshotPolicyId": { - "type": "string", - "metadata": { - "description": "Optional. Snapshot Policy ResourceId." - } - }, - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot policy." - } - }, - "snapshotPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the snapshot policy." - } - }, "dailyHour": { "type": "int", "metadata": { @@ -790,11 +714,79 @@ }, "snapEnabled": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { "description": "Optional. Indicates whether the snapshot policy is enabled." } }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "backupVaultLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the backup vault." + } + }, + "backupName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupLabel": { + "type": "string", + "metadata": { + "description": "Optional. The label of the backup." + } + }, + "useExistingSnapshot": { + "type": "bool", + "metadata": { + "description": "Optional. Indicates whether to use an existing snapshot." + } + }, + "snapshotName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "snapshotPolicyId": { + "type": "string", + "metadata": { + "description": "Optional. The snapshot Policy id." + } + }, "volumeResourceId": { "type": "string", "metadata": { @@ -829,6 +821,25 @@ "description": "Optional. Zone where the volume will be placed." } }, + "policyEnforced": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If Backup policy is enforced." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The backup policy location." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of snashot policies." + } + }, "serviceLevel": { "type": "string", "defaultValue": "Standard", @@ -893,6 +904,19 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "backupVaultId": { + "type": "string", + "metadata": { + "description": "Optional. The Id of the Backup Vault." + } + }, + "replicationEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Boolean to enable replication." + } } }, "variables": { @@ -932,64 +956,13 @@ "apiVersion": "2024-03-01", "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", "location": "[parameters('location')]", - "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), 'snapshot', createObject('snapshotPolicyId', parameters('snapshotPolicyId')))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", + "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', if(parameters('replicationEnabled'), createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), createObject()), 'backup', if(parameters('backupEnabled'), createObject('backupPolicyId', reference('backupPolicies').outputs.resourceId.value, 'policyEnforced', parameters('policyEnforced'), 'backupVaultId', parameters('backupVaultId')), createObject()), 'snapshot', if(parameters('snapEnabled'), createObject('snapshotPolicyId', reference('snapshotPolicies').outputs.resourceId.value), createObject()))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", "zones": "[parameters('zones')]", "dependsOn": [ - "netAppAccount::capacityPool" - ] - }, - "snapshotPolicies": { - "condition": "[parameters('snapEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", - "location": "[parameters('snapshotPolicyLocation')]", - "properties": { - "enabled": "[parameters('snapEnabled')]", - "dailySchedule": { - "hour": "[parameters('dailyHour')]", - "minute": "[parameters('dailyMinute')]", - "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", - "usedBytes": "[parameters('dailyUsedBytes')]" - }, - "hourlySchedule": { - "minute": "[parameters('hourlyMinute')]", - "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", - "usedBytes": "[parameters('hourlyUsedBytes')]" - }, - "monthlySchedule": { - "daysOfMonth": "[parameters('daysOfMonth')]", - "hour": "[parameters('monthlyHour')]", - "minute": "[parameters('monthlyMinute')]", - "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", - "usedBytes": "[parameters('monthlyUsedBytes')]" - }, - "weeklySchedule": { - "day": "[parameters('weeklyDay')]", - "hour": "[parameters('weeklyHour')]", - "minute": "[parameters('weeklyMinute')]", - "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", - "usedBytes": "[parameters('weeklyUsedBytes')]" - } - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "backupPolicies": { - "condition": "[parameters('backupEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", - "location": "[parameters('backupPolicyLocation')]", - "properties": { - "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", - "enabled": "[parameters('backupEnabled')]", - "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", - "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" - }, - "dependsOn": [ - "netAppAccount" + "backupPolicies", + "backupVaults", + "netAppAccount::capacityPool", + "snapshotPolicies" ] }, "backupVaults": { @@ -1010,7 +983,8 @@ "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('backupName'))]", "properties": "[if(parameters('backupEnabled'), createObject('label', parameters('backupLabel'), 'snapshotName', parameters('snapshotName'), 'useExistingSnapshot', parameters('useExistingSnapshot'), 'volumeResourceId', parameters('volumeResourceId')), createObject())]", "dependsOn": [ - "backupVaults" + "backupVaults", + "volume" ] }, "volume_roleAssignments": { @@ -1034,6 +1008,413 @@ "dependsOn": [ "volume" ] + }, + "backupPolicies": { + "condition": "[parameters('backupEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('backupPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyBackupsToKeep": { + "value": "[parameters('dailyBackupsToKeep')]" + }, + "monthlyBackupsToKeep": { + "value": "[parameters('monthlyBackupsToKeep')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "weeklyBackupsToKeep": { + "value": "[parameters('weeklyBackupsToKeep')]" + }, + "backupEnabled": { + "value": "[parameters('backupEnabled')]" + }, + "backupPolicyLocation": { + "value": "[parameters('backupPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "16399924782439066553" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Required. The name of the backup policy." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of the backup policy. Required if the template is used in a standalone deployment." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", + "location": "[parameters('backupPolicyLocation')]", + "properties": { + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "enabled": "[parameters('backupEnabled')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the backup Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), parameters('backupPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('backupPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Backup Policy was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } + }, + "snapshotPolicies": { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[uniqueString(parameters('snapshotPolicyName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyHour": { + "value": "[parameters('dailyHour')]" + }, + "dailyMinute": { + "value": "[parameters('dailyMinute')]" + }, + "dailySnapshotsToKeep": { + "value": "[parameters('dailySnapshotsToKeep')]" + }, + "dailyUsedBytes": { + "value": "[parameters('dailyUsedBytes')]" + }, + "daysOfMonth": { + "value": "[parameters('daysOfMonth')]" + }, + "hourlyMinute": { + "value": "[parameters('hourlyMinute')]" + }, + "hourlySnapshotsToKeep": { + "value": "[parameters('hourlySnapshotsToKeep')]" + }, + "hourlyUsedBytes": { + "value": "[parameters('hourlyUsedBytes')]" + }, + "monthlyHour": { + "value": "[parameters('monthlyHour')]" + }, + "monthlyMinute": { + "value": "[parameters('monthlyMinute')]" + }, + "monthlySnapshotsToKeep": { + "value": "[parameters('monthlySnapshotsToKeep')]" + }, + "monthlyUsedBytes": { + "value": "[parameters('monthlyUsedBytes')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "snapshotPolicyName": { + "value": "[parameters('snapshotPolicyName')]" + }, + "weeklyDay": { + "value": "[parameters('weeklyDay')]" + }, + "weeklyHour": { + "value": "[parameters('weeklyHour')]" + }, + "weeklyMinute": { + "value": "[parameters('weeklyMinute')]" + }, + "weeklySnapshotsToKeep": { + "value": "[parameters('weeklySnapshotsToKeep')]" + }, + "weeklyUsedBytes": { + "value": "[parameters('weeklyUsedBytes')]" + }, + "snapshotPolicyLocation": { + "value": "[parameters('snapshotPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "17076752505050697613" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "dailyHour": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot hour." + } + }, + "dailyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot minute." + } + }, + "dailySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot count to keep." + } + }, + "dailyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot used bytes." + } + }, + "hourlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The hourly snapshot minute." + } + }, + "hourlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot count to keep." + } + }, + "hourlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot used bytes." + } + }, + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Optional. The monthly snapshot day." + } + }, + "monthlyHour": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot hour." + } + }, + "monthlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot minute." + } + }, + "monthlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot count to keep." + } + }, + "monthlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot used bytes." + } + }, + "weeklyDay": { + "type": "string", + "metadata": { + "description": "Optional. The weekly snapshot day." + } + }, + "weeklyHour": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot hour." + } + }, + "weeklyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot minute." + } + }, + "weeklySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot count to keep." + } + }, + "weeklyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot used bytes." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": [ + { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", + "location": "[parameters('snapshotPolicyLocation')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": { + "hour": "[parameters('dailyHour')]", + "minute": "[parameters('dailyMinute')]", + "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", + "usedBytes": "[parameters('dailyUsedBytes')]" + }, + "hourlySchedule": { + "minute": "[parameters('hourlyMinute')]", + "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", + "usedBytes": "[parameters('hourlyUsedBytes')]" + }, + "monthlySchedule": { + "daysOfMonth": "[parameters('daysOfMonth')]", + "hour": "[parameters('monthlyHour')]", + "minute": "[parameters('monthlyMinute')]", + "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", + "usedBytes": "[parameters('monthlyUsedBytes')]" + }, + "weeklySchedule": { + "day": "[parameters('weeklyDay')]", + "hour": "[parameters('weeklyHour')]", + "minute": "[parameters('weeklyMinute')]", + "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", + "usedBytes": "[parameters('weeklyUsedBytes')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the snapshot Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('snapshotPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Snapshot was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } } }, "outputs": { diff --git a/avm/res/net-app/net-app-account/capacity-pool/volume/README.md b/avm/res/net-app/net-app-account/capacity-pool/volume/README.md index 9361b0045e..de7e5a1c46 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/volume/README.md +++ b/avm/res/net-app/net-app-account/capacity-pool/volume/README.md @@ -7,6 +7,7 @@ This module deploys an Azure NetApp Files Capacity Pool Volume. - [Resource Types](#Resource-Types) - [Parameters](#Parameters) - [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) ## Resource Types @@ -43,8 +44,9 @@ This module deploys an Azure NetApp Files Capacity Pool Volume. | [`backupEnabled`](#parameter-backupenabled) | bool | Indicates whether the backup policy is enabled. | | [`backupLabel`](#parameter-backuplabel) | string | The label of the backup. | | [`backupName`](#parameter-backupname) | string | The name of the backup. | -| [`backupPolicyLocation`](#parameter-backuppolicylocation) | string | The location of the backup policy. | +| [`backupPolicyLocation`](#parameter-backuppolicylocation) | string | The backup policy location. | | [`backupPolicyName`](#parameter-backuppolicyname) | string | The name of the backup policy. | +| [`backupVaultId`](#parameter-backupvaultid) | string | The Id of the Backup Vault. | | [`backupVaultLocation`](#parameter-backupvaultlocation) | string | The location of the backup vault. | | [`backupVaultName`](#parameter-backupvaultname) | string | The name of the backup vault. | | [`coolAccess`](#parameter-coolaccess) | bool | If enabled (true) the pool can contain cool Access enabled volumes. | @@ -71,16 +73,18 @@ This module deploys an Azure NetApp Files Capacity Pool Volume. | [`monthlySnapshotsToKeep`](#parameter-monthlysnapshotstokeep) | int | Monthly snapshot count to keep. | | [`monthlyUsedBytes`](#parameter-monthlyusedbytes) | int | Monthly snapshot used bytes. | | [`networkFeatures`](#parameter-networkfeatures) | string | Network feature for the volume. | +| [`policyEnforced`](#parameter-policyenforced) | bool | If Backup policy is enforced. | | [`protocolTypes`](#parameter-protocoltypes) | array | Set of protocol types. | | [`remoteVolumeRegion`](#parameter-remotevolumeregion) | string | The remote region for the other end of the Volume Replication. | | [`remoteVolumeResourceId`](#parameter-remotevolumeresourceid) | string | The resource ID of the remote volume. | +| [`replicationEnabled`](#parameter-replicationenabled) | bool | Boolean to enable replication. | | [`replicationSchedule`](#parameter-replicationschedule) | string | The replication schedule for the volume. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`serviceLevel`](#parameter-servicelevel) | string | The pool service level. Must match the one of the parent capacity pool. | | [`snapEnabled`](#parameter-snapenabled) | bool | Indicates whether the snapshot policy is enabled. | | [`snapshotName`](#parameter-snapshotname) | string | The name of the snapshot. | -| [`snapshotPolicyId`](#parameter-snapshotpolicyid) | string | Snapshot Policy ResourceId. | -| [`snapshotPolicyLocation`](#parameter-snapshotpolicylocation) | string | The location of the snapshot policy. | +| [`snapshotPolicyId`](#parameter-snapshotpolicyid) | string | The snapshot Policy id. | +| [`snapshotPolicyLocation`](#parameter-snapshotpolicylocation) | string | The location of snashot policies. | | [`snapshotPolicyName`](#parameter-snapshotpolicyname) | string | The name of the snapshot policy. | | [`useExistingSnapshot`](#parameter-useexistingsnapshot) | bool | Indicates whether to use an existing snapshot. | | [`volumeResourceId`](#parameter-volumeresourceid) | string | The resource ID of the volume. | @@ -152,11 +156,10 @@ The name of the backup. ### Parameter: `backupPolicyLocation` -The location of the backup policy. +The backup policy location. -- Required: No +- Required: Yes - Type: string -- Default: `[resourceGroup().location]` ### Parameter: `backupPolicyName` @@ -166,6 +169,13 @@ The name of the backup policy. - Type: string - Default: `'backupPolicy'` +### Parameter: `backupVaultId` + +The Id of the Backup Vault. + +- Required: Yes +- Type: string + ### Parameter: `backupVaultLocation` The location of the backup vault. @@ -364,6 +374,14 @@ Network feature for the volume. ] ``` +### Parameter: `policyEnforced` + +If Backup policy is enforced. + +- Required: No +- Type: bool +- Default: `False` + ### Parameter: `protocolTypes` Set of protocol types. @@ -386,6 +404,14 @@ The resource ID of the remote volume. - Required: Yes - Type: string +### Parameter: `replicationEnabled` + +Boolean to enable replication. + +- Required: No +- Type: bool +- Default: `True` + ### Parameter: `replicationSchedule` The replication schedule for the volume. @@ -519,7 +545,7 @@ Indicates whether the snapshot policy is enabled. - Required: No - Type: bool -- Default: `False` +- Default: `True` ### Parameter: `snapshotName` @@ -530,18 +556,17 @@ The name of the snapshot. ### Parameter: `snapshotPolicyId` -Snapshot Policy ResourceId. +The snapshot Policy id. - Required: Yes - Type: string ### Parameter: `snapshotPolicyLocation` -The location of the snapshot policy. +The location of snashot policies. -- Required: No +- Required: Yes - Type: string -- Default: `[resourceGroup().location]` ### Parameter: `snapshotPolicyName` @@ -634,3 +659,12 @@ Zone where the volume will be placed. | `name` | string | The name of the Volume. | | `resourceGroupName` | string | The name of the Resource Group the Volume was created in. | | `resourceId` | string | The Resource ID of the Volume. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `res/net-app/net-app-account/backup-policies` | Local reference | +| `res/net-app/net-app-account/snapshot-policies` | Local reference | diff --git a/avm/res/net-app/net-app-account/capacity-pool/volume/main.bicep b/avm/res/net-app/net-app-account/capacity-pool/volume/main.bicep index 8143e6e448..ce5de13b21 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/volume/main.bicep +++ b/avm/res/net-app/net-app-account/capacity-pool/volume/main.bicep @@ -41,45 +41,6 @@ param backupEnabled bool = false @description('Optional. The name of the backup policy.') param backupPolicyName string = 'backupPolicy' -@description('Optional. The location of the backup policy.') -param backupPolicyLocation string = resourceGroup().location - -@description('Optional. The daily backups to keep.') -param dailyBackupsToKeep int - -@description('Optional. The monthly backups to keep.') -param monthlyBackupsToKeep int - -@description('Optional. The weekly backups to keep.') -param weeklyBackupsToKeep int - -@description('Optional. The name of the backup vault.') -param backupVaultName string = 'vault' - -@description('Optional. The location of the backup vault.') -param backupVaultLocation string = resourceGroup().location - -@description('Optional. The name of the backup.') -param backupName string - -@description('Optional. The label of the backup.') -param backupLabel string - -@description('Optional. Indicates whether to use an existing snapshot.') -param useExistingSnapshot bool - -@description('Optional. The name of the snapshot.') -param snapshotName string - -@description('Optional. Snapshot Policy ResourceId.') -param snapshotPolicyId string - -@description('Optional. The name of the snapshot policy.') -param snapshotPolicyName string - -@description('Optional. The location of the snapshot policy.') -param snapshotPolicyLocation string = resourceGroup().location - @description('Optional. The daily snapshot hour.') param dailyHour int @@ -132,7 +93,40 @@ param weeklySnapshotsToKeep int param weeklyUsedBytes int @description('Optional. Indicates whether the snapshot policy is enabled.') -param snapEnabled bool = false +param snapEnabled bool = true + +@description('Optional. The name of the snapshot policy.') +param snapshotPolicyName string + +@description('Optional. The daily backups to keep.') +param dailyBackupsToKeep int + +@description('Optional. The monthly backups to keep.') +param monthlyBackupsToKeep int + +@description('Optional. The weekly backups to keep.') +param weeklyBackupsToKeep int + +@description('Optional. The name of the backup vault.') +param backupVaultName string = 'vault' + +@description('Optional. The location of the backup vault.') +param backupVaultLocation string = resourceGroup().location + +@description('Optional. The name of the backup.') +param backupName string + +@description('Optional. The label of the backup.') +param backupLabel string + +@description('Optional. Indicates whether to use an existing snapshot.') +param useExistingSnapshot bool + +@description('Optional. The name of the snapshot.') +param snapshotName string + +@description('Optional. The snapshot Policy id.') +param snapshotPolicyId string @description('Optional. The resource ID of the volume.') param volumeResourceId string @@ -149,6 +143,15 @@ param location string = resourceGroup().location @description('Optional. Zone where the volume will be placed.') param zones array = ['1'] +@description('Optional. If Backup policy is enforced.') +param policyEnforced bool = false + +@description('Optional. The backup policy location.') +param backupPolicyLocation string + +@description('Optional. The location of snashot policies.') +param snapshotPolicyLocation string + @description('Optional. The pool service level. Must match the one of the parent capacity pool.') @allowed([ 'Premium' @@ -185,6 +188,12 @@ param exportPolicyRules array = [] @description('Optional. Array of role assignments to create.') param roleAssignments roleAssignmentType +@description('Optional. The Id of the Backup Vault.') +param backupVaultId string + +@description('Optional. Boolean to enable replication.') +param replicationEnabled bool = true + var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') @@ -222,6 +231,10 @@ resource volume 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes@2024-03-0 name: name parent: netAppAccount::capacityPool location: location + dependsOn: [ + backupVaults + backupPolicies + ] properties: { coolAccess: coolAccess coolAccessRetrievalPolicy: coolAccessRetrievalPolicy @@ -236,15 +249,27 @@ resource volume 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes@2024-03-0 ? { volumeType: volumeType dataProtection: { - replication: { - endpointType: endpointType - remoteVolumeRegion: remoteVolumeRegion - remoteVolumeResourceId: remoteVolumeResourceId - replicationSchedule: replicationSchedule - } - snapshot: { - snapshotPolicyId: snapshotPolicyId - } + replication: replicationEnabled + ? { + endpointType: endpointType + remoteVolumeRegion: remoteVolumeRegion + remoteVolumeResourceId: remoteVolumeResourceId + replicationSchedule: replicationSchedule + } + : {} + + backup: backupEnabled + ? { + backupPolicyId: backupPolicies.outputs.resourceId + policyEnforced: policyEnforced + backupVaultId: backupVaultId + } + : {} + snapshot: snapEnabled + ? { + snapshotPolicyId: snapshotPolicies.outputs.resourceId + } + : {} } } : {}) @@ -263,49 +288,41 @@ resource volume 'Microsoft.NetApp/netAppAccounts/capacityPools/volumes@2024-03-0 zones: zones } -resource snapshotPolicies 'Microsoft.NetApp/netAppAccounts/snapshotPolicies@2024-03-01' = if (snapEnabled) { - name: snapshotPolicyName - parent: netAppAccount - location: snapshotPolicyLocation - properties: { - enabled: snapEnabled - dailySchedule: { - hour: dailyHour - minute: dailyMinute - snapshotsToKeep: dailySnapshotsToKeep - usedBytes: dailyUsedBytes - } - hourlySchedule: { - minute: hourlyMinute - snapshotsToKeep: hourlySnapshotsToKeep - usedBytes: hourlyUsedBytes - } - monthlySchedule: { - daysOfMonth: daysOfMonth - hour: monthlyHour - minute: monthlyMinute - snapshotsToKeep: monthlySnapshotsToKeep - usedBytes: monthlyUsedBytes - } - weeklySchedule: { - day: weeklyDay - hour: weeklyHour - minute: weeklyMinute - snapshotsToKeep: weeklySnapshotsToKeep - usedBytes: weeklyUsedBytes - } - } -} - -resource backupPolicies 'Microsoft.NetApp/netAppAccounts/backupPolicies@2024-03-01' = if (backupEnabled) { +module backupPolicies '../../backup-policies/main.bicep' = if (backupEnabled) { name: backupPolicyName - parent: netAppAccount - location: backupPolicyLocation - properties: { + params: { dailyBackupsToKeep: dailyBackupsToKeep - enabled: backupEnabled monthlyBackupsToKeep: monthlyBackupsToKeep + netAppAccountName: netAppAccountName weeklyBackupsToKeep: weeklyBackupsToKeep + backupEnabled: backupEnabled + backupPolicyLocation: backupPolicyLocation + } +} + +module snapshotPolicies '../../snapshot-policies/main.bicep' = if (snapEnabled) { + name: uniqueString(snapshotPolicyName) + params: { + dailyHour: dailyHour + dailyMinute: dailyMinute + dailySnapshotsToKeep: dailySnapshotsToKeep + dailyUsedBytes: dailyUsedBytes + daysOfMonth: daysOfMonth + hourlyMinute: hourlyMinute + hourlySnapshotsToKeep: hourlySnapshotsToKeep + hourlyUsedBytes: hourlyUsedBytes + monthlyHour: monthlyHour + monthlyMinute: monthlyMinute + monthlySnapshotsToKeep: monthlySnapshotsToKeep + monthlyUsedBytes: monthlyUsedBytes + netAppAccountName: netAppAccountName + snapshotPolicyName: snapshotPolicyName + weeklyDay: weeklyDay + weeklyHour: weeklyHour + weeklyMinute: weeklyMinute + weeklySnapshotsToKeep: weeklySnapshotsToKeep + weeklyUsedBytes: weeklyUsedBytes + snapshotPolicyLocation: snapshotPolicyLocation } } @@ -319,6 +336,9 @@ resource backupVaults 'Microsoft.NetApp/netAppAccounts/backupVaults@2024-03-01' resource backups 'Microsoft.NetApp/netAppAccounts/backupVaults/backups@2024-03-01' = if (backupEnabled) { name: backupName parent: backupVaults + dependsOn: [ + volume + ] properties: backupEnabled ? { label: backupLabel diff --git a/avm/res/net-app/net-app-account/capacity-pool/volume/main.json b/avm/res/net-app/net-app-account/capacity-pool/volume/main.json index 0e32725463..dbbbaa682f 100644 --- a/avm/res/net-app/net-app-account/capacity-pool/volume/main.json +++ b/avm/res/net-app/net-app-account/capacity-pool/volume/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18098024822158530053" + "version": "0.30.3.12046", + "templateHash": "3878108397799577614" }, "name": "Azure NetApp Files Capacity Pool Volumes", "description": "This module deploys an Azure NetApp Files Capacity Pool Volume.", @@ -169,88 +169,6 @@ "description": "Optional. The name of the backup policy." } }, - "backupPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup policy." - } - }, - "dailyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The daily backups to keep." - } - }, - "monthlyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The monthly backups to keep." - } - }, - "weeklyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The weekly backups to keep." - } - }, - "backupVaultName": { - "type": "string", - "defaultValue": "vault", - "metadata": { - "description": "Optional. The name of the backup vault." - } - }, - "backupVaultLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup vault." - } - }, - "backupName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "backupLabel": { - "type": "string", - "metadata": { - "description": "Optional. The label of the backup." - } - }, - "useExistingSnapshot": { - "type": "bool", - "metadata": { - "description": "Optional. Indicates whether to use an existing snapshot." - } - }, - "snapshotName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "snapshotPolicyId": { - "type": "string", - "metadata": { - "description": "Optional. Snapshot Policy ResourceId." - } - }, - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot policy." - } - }, - "snapshotPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the snapshot policy." - } - }, "dailyHour": { "type": "int", "metadata": { @@ -355,11 +273,79 @@ }, "snapEnabled": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { "description": "Optional. Indicates whether the snapshot policy is enabled." } }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "backupVaultLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the backup vault." + } + }, + "backupName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupLabel": { + "type": "string", + "metadata": { + "description": "Optional. The label of the backup." + } + }, + "useExistingSnapshot": { + "type": "bool", + "metadata": { + "description": "Optional. Indicates whether to use an existing snapshot." + } + }, + "snapshotName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "snapshotPolicyId": { + "type": "string", + "metadata": { + "description": "Optional. The snapshot Policy id." + } + }, "volumeResourceId": { "type": "string", "metadata": { @@ -394,6 +380,25 @@ "description": "Optional. Zone where the volume will be placed." } }, + "policyEnforced": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If Backup policy is enforced." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The backup policy location." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of snashot policies." + } + }, "serviceLevel": { "type": "string", "defaultValue": "Standard", @@ -458,6 +463,19 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "backupVaultId": { + "type": "string", + "metadata": { + "description": "Optional. The Id of the Backup Vault." + } + }, + "replicationEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Boolean to enable replication." + } } }, "variables": { @@ -497,64 +515,13 @@ "apiVersion": "2024-03-01", "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", "location": "[parameters('location')]", - "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), 'snapshot', createObject('snapshotPolicyId', parameters('snapshotPolicyId')))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", + "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', if(parameters('replicationEnabled'), createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), createObject()), 'backup', if(parameters('backupEnabled'), createObject('backupPolicyId', reference('backupPolicies').outputs.resourceId.value, 'policyEnforced', parameters('policyEnforced'), 'backupVaultId', parameters('backupVaultId')), createObject()), 'snapshot', if(parameters('snapEnabled'), createObject('snapshotPolicyId', reference('snapshotPolicies').outputs.resourceId.value), createObject()))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", "zones": "[parameters('zones')]", "dependsOn": [ - "netAppAccount::capacityPool" - ] - }, - "snapshotPolicies": { - "condition": "[parameters('snapEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", - "location": "[parameters('snapshotPolicyLocation')]", - "properties": { - "enabled": "[parameters('snapEnabled')]", - "dailySchedule": { - "hour": "[parameters('dailyHour')]", - "minute": "[parameters('dailyMinute')]", - "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", - "usedBytes": "[parameters('dailyUsedBytes')]" - }, - "hourlySchedule": { - "minute": "[parameters('hourlyMinute')]", - "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", - "usedBytes": "[parameters('hourlyUsedBytes')]" - }, - "monthlySchedule": { - "daysOfMonth": "[parameters('daysOfMonth')]", - "hour": "[parameters('monthlyHour')]", - "minute": "[parameters('monthlyMinute')]", - "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", - "usedBytes": "[parameters('monthlyUsedBytes')]" - }, - "weeklySchedule": { - "day": "[parameters('weeklyDay')]", - "hour": "[parameters('weeklyHour')]", - "minute": "[parameters('weeklyMinute')]", - "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", - "usedBytes": "[parameters('weeklyUsedBytes')]" - } - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "backupPolicies": { - "condition": "[parameters('backupEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", - "location": "[parameters('backupPolicyLocation')]", - "properties": { - "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", - "enabled": "[parameters('backupEnabled')]", - "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", - "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" - }, - "dependsOn": [ - "netAppAccount" + "backupPolicies", + "backupVaults", + "netAppAccount::capacityPool", + "snapshotPolicies" ] }, "backupVaults": { @@ -575,7 +542,8 @@ "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('backupName'))]", "properties": "[if(parameters('backupEnabled'), createObject('label', parameters('backupLabel'), 'snapshotName', parameters('snapshotName'), 'useExistingSnapshot', parameters('useExistingSnapshot'), 'volumeResourceId', parameters('volumeResourceId')), createObject())]", "dependsOn": [ - "backupVaults" + "backupVaults", + "volume" ] }, "volume_roleAssignments": { @@ -599,6 +567,413 @@ "dependsOn": [ "volume" ] + }, + "backupPolicies": { + "condition": "[parameters('backupEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('backupPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyBackupsToKeep": { + "value": "[parameters('dailyBackupsToKeep')]" + }, + "monthlyBackupsToKeep": { + "value": "[parameters('monthlyBackupsToKeep')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "weeklyBackupsToKeep": { + "value": "[parameters('weeklyBackupsToKeep')]" + }, + "backupEnabled": { + "value": "[parameters('backupEnabled')]" + }, + "backupPolicyLocation": { + "value": "[parameters('backupPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "16399924782439066553" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Required. The name of the backup policy." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of the backup policy. Required if the template is used in a standalone deployment." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", + "location": "[parameters('backupPolicyLocation')]", + "properties": { + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "enabled": "[parameters('backupEnabled')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the backup Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), parameters('backupPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('backupPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Backup Policy was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } + }, + "snapshotPolicies": { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[uniqueString(parameters('snapshotPolicyName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyHour": { + "value": "[parameters('dailyHour')]" + }, + "dailyMinute": { + "value": "[parameters('dailyMinute')]" + }, + "dailySnapshotsToKeep": { + "value": "[parameters('dailySnapshotsToKeep')]" + }, + "dailyUsedBytes": { + "value": "[parameters('dailyUsedBytes')]" + }, + "daysOfMonth": { + "value": "[parameters('daysOfMonth')]" + }, + "hourlyMinute": { + "value": "[parameters('hourlyMinute')]" + }, + "hourlySnapshotsToKeep": { + "value": "[parameters('hourlySnapshotsToKeep')]" + }, + "hourlyUsedBytes": { + "value": "[parameters('hourlyUsedBytes')]" + }, + "monthlyHour": { + "value": "[parameters('monthlyHour')]" + }, + "monthlyMinute": { + "value": "[parameters('monthlyMinute')]" + }, + "monthlySnapshotsToKeep": { + "value": "[parameters('monthlySnapshotsToKeep')]" + }, + "monthlyUsedBytes": { + "value": "[parameters('monthlyUsedBytes')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "snapshotPolicyName": { + "value": "[parameters('snapshotPolicyName')]" + }, + "weeklyDay": { + "value": "[parameters('weeklyDay')]" + }, + "weeklyHour": { + "value": "[parameters('weeklyHour')]" + }, + "weeklyMinute": { + "value": "[parameters('weeklyMinute')]" + }, + "weeklySnapshotsToKeep": { + "value": "[parameters('weeklySnapshotsToKeep')]" + }, + "weeklyUsedBytes": { + "value": "[parameters('weeklyUsedBytes')]" + }, + "snapshotPolicyLocation": { + "value": "[parameters('snapshotPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "17076752505050697613" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "dailyHour": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot hour." + } + }, + "dailyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot minute." + } + }, + "dailySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot count to keep." + } + }, + "dailyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot used bytes." + } + }, + "hourlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The hourly snapshot minute." + } + }, + "hourlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot count to keep." + } + }, + "hourlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot used bytes." + } + }, + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Optional. The monthly snapshot day." + } + }, + "monthlyHour": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot hour." + } + }, + "monthlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot minute." + } + }, + "monthlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot count to keep." + } + }, + "monthlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot used bytes." + } + }, + "weeklyDay": { + "type": "string", + "metadata": { + "description": "Optional. The weekly snapshot day." + } + }, + "weeklyHour": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot hour." + } + }, + "weeklyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot minute." + } + }, + "weeklySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot count to keep." + } + }, + "weeklyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot used bytes." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": [ + { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", + "location": "[parameters('snapshotPolicyLocation')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": { + "hour": "[parameters('dailyHour')]", + "minute": "[parameters('dailyMinute')]", + "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", + "usedBytes": "[parameters('dailyUsedBytes')]" + }, + "hourlySchedule": { + "minute": "[parameters('hourlyMinute')]", + "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", + "usedBytes": "[parameters('hourlyUsedBytes')]" + }, + "monthlySchedule": { + "daysOfMonth": "[parameters('daysOfMonth')]", + "hour": "[parameters('monthlyHour')]", + "minute": "[parameters('monthlyMinute')]", + "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", + "usedBytes": "[parameters('monthlyUsedBytes')]" + }, + "weeklySchedule": { + "day": "[parameters('weeklyDay')]", + "hour": "[parameters('weeklyHour')]", + "minute": "[parameters('weeklyMinute')]", + "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", + "usedBytes": "[parameters('weeklyUsedBytes')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the snapshot Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('snapshotPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Snapshot was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } } }, "outputs": { diff --git a/avm/res/net-app/net-app-account/main.json b/avm/res/net-app/net-app-account/main.json index afe617cbcf..c260cb81ba 100644 --- a/avm/res/net-app/net-app-account/main.json +++ b/avm/res/net-app/net-app-account/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "5247980225087680814" + "version": "0.30.3.12046", + "templateHash": "6577593938028395411" }, "name": "Azure NetApp Files", "description": "This module deploys an Azure NetApp File.", @@ -503,8 +503,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "8361786183534097212" + "version": "0.30.3.12046", + "templateHash": "5120059204101466005" }, "name": "Azure NetApp Files Capacity Pools", "description": "This module deploys an Azure NetApp Files Capacity Pool.", @@ -929,6 +929,12 @@ }, "volumeType": { "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'volumeType'), '')]" + }, + "backupVaultId": { + "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'backupVaultId'), '')]" + }, + "replicationEnabled": { + "value": "[coalesce(tryGet(parameters('volumes')[copyIndex()], 'replicationEnabled'), false())]" } }, "template": { @@ -938,8 +944,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.29.47.4906", - "templateHash": "18098024822158530053" + "version": "0.30.3.12046", + "templateHash": "3878108397799577614" }, "name": "Azure NetApp Files Capacity Pool Volumes", "description": "This module deploys an Azure NetApp Files Capacity Pool Volume.", @@ -1102,88 +1108,6 @@ "description": "Optional. The name of the backup policy." } }, - "backupPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup policy." - } - }, - "dailyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The daily backups to keep." - } - }, - "monthlyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The monthly backups to keep." - } - }, - "weeklyBackupsToKeep": { - "type": "int", - "metadata": { - "description": "Optional. The weekly backups to keep." - } - }, - "backupVaultName": { - "type": "string", - "defaultValue": "vault", - "metadata": { - "description": "Optional. The name of the backup vault." - } - }, - "backupVaultLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the backup vault." - } - }, - "backupName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the backup." - } - }, - "backupLabel": { - "type": "string", - "metadata": { - "description": "Optional. The label of the backup." - } - }, - "useExistingSnapshot": { - "type": "bool", - "metadata": { - "description": "Optional. Indicates whether to use an existing snapshot." - } - }, - "snapshotName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot." - } - }, - "snapshotPolicyId": { - "type": "string", - "metadata": { - "description": "Optional. Snapshot Policy ResourceId." - } - }, - "snapshotPolicyName": { - "type": "string", - "metadata": { - "description": "Optional. The name of the snapshot policy." - } - }, - "snapshotPolicyLocation": { - "type": "string", - "defaultValue": "[resourceGroup().location]", - "metadata": { - "description": "Optional. The location of the snapshot policy." - } - }, "dailyHour": { "type": "int", "metadata": { @@ -1288,11 +1212,79 @@ }, "snapEnabled": { "type": "bool", - "defaultValue": false, + "defaultValue": true, "metadata": { "description": "Optional. Indicates whether the snapshot policy is enabled." } }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupVaultName": { + "type": "string", + "defaultValue": "vault", + "metadata": { + "description": "Optional. The name of the backup vault." + } + }, + "backupVaultLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the backup vault." + } + }, + "backupName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the backup." + } + }, + "backupLabel": { + "type": "string", + "metadata": { + "description": "Optional. The label of the backup." + } + }, + "useExistingSnapshot": { + "type": "bool", + "metadata": { + "description": "Optional. Indicates whether to use an existing snapshot." + } + }, + "snapshotName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot." + } + }, + "snapshotPolicyId": { + "type": "string", + "metadata": { + "description": "Optional. The snapshot Policy id." + } + }, "volumeResourceId": { "type": "string", "metadata": { @@ -1327,6 +1319,25 @@ "description": "Optional. Zone where the volume will be placed." } }, + "policyEnforced": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If Backup policy is enforced." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The backup policy location." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of snashot policies." + } + }, "serviceLevel": { "type": "string", "defaultValue": "Standard", @@ -1391,6 +1402,19 @@ "metadata": { "description": "Optional. Array of role assignments to create." } + }, + "backupVaultId": { + "type": "string", + "metadata": { + "description": "Optional. The Id of the Backup Vault." + } + }, + "replicationEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Boolean to enable replication." + } } }, "variables": { @@ -1430,64 +1454,13 @@ "apiVersion": "2024-03-01", "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('capacityPoolName'), parameters('name'))]", "location": "[parameters('location')]", - "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), 'snapshot', createObject('snapshotPolicyId', parameters('snapshotPolicyId')))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", + "properties": "[shallowMerge(createArray(createObject('coolAccess', parameters('coolAccess'), 'coolAccessRetrievalPolicy', parameters('coolAccessRetrievalPolicy'), 'coolnessPeriod', parameters('coolnessPeriod'), 'encryptionKeySource', parameters('encryptionKeySource')), if(not(equals(parameters('encryptionKeySource'), 'Microsoft.NetApp')), createObject('keyVaultPrivateEndpointResourceId', parameters('keyVaultPrivateEndpointResourceId')), createObject()), if(not(equals(parameters('volumeType'), '')), createObject('volumeType', parameters('volumeType'), 'dataProtection', createObject('replication', if(parameters('replicationEnabled'), createObject('endpointType', parameters('endpointType'), 'remoteVolumeRegion', parameters('remoteVolumeRegion'), 'remoteVolumeResourceId', parameters('remoteVolumeResourceId'), 'replicationSchedule', parameters('replicationSchedule')), createObject()), 'backup', if(parameters('backupEnabled'), createObject('backupPolicyId', reference('backupPolicies').outputs.resourceId.value, 'policyEnforced', parameters('policyEnforced'), 'backupVaultId', parameters('backupVaultId')), createObject()), 'snapshot', if(parameters('snapEnabled'), createObject('snapshotPolicyId', reference('snapshotPolicies').outputs.resourceId.value), createObject()))), createObject()), createObject('networkFeatures', parameters('networkFeatures'), 'serviceLevel', parameters('serviceLevel'), 'creationToken', parameters('creationToken'), 'usageThreshold', parameters('usageThreshold'), 'protocolTypes', parameters('protocolTypes'), 'subnetId', parameters('subnetResourceId'), 'exportPolicy', if(not(empty(parameters('exportPolicyRules'))), createObject('rules', parameters('exportPolicyRules')), null()))))]", "zones": "[parameters('zones')]", "dependsOn": [ - "netAppAccount::capacityPool" - ] - }, - "snapshotPolicies": { - "condition": "[parameters('snapEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", - "location": "[parameters('snapshotPolicyLocation')]", - "properties": { - "enabled": "[parameters('snapEnabled')]", - "dailySchedule": { - "hour": "[parameters('dailyHour')]", - "minute": "[parameters('dailyMinute')]", - "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", - "usedBytes": "[parameters('dailyUsedBytes')]" - }, - "hourlySchedule": { - "minute": "[parameters('hourlyMinute')]", - "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", - "usedBytes": "[parameters('hourlyUsedBytes')]" - }, - "monthlySchedule": { - "daysOfMonth": "[parameters('daysOfMonth')]", - "hour": "[parameters('monthlyHour')]", - "minute": "[parameters('monthlyMinute')]", - "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", - "usedBytes": "[parameters('monthlyUsedBytes')]" - }, - "weeklySchedule": { - "day": "[parameters('weeklyDay')]", - "hour": "[parameters('weeklyHour')]", - "minute": "[parameters('weeklyMinute')]", - "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", - "usedBytes": "[parameters('weeklyUsedBytes')]" - } - }, - "dependsOn": [ - "netAppAccount" - ] - }, - "backupPolicies": { - "condition": "[parameters('backupEnabled')]", - "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", - "apiVersion": "2024-03-01", - "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", - "location": "[parameters('backupPolicyLocation')]", - "properties": { - "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", - "enabled": "[parameters('backupEnabled')]", - "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", - "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" - }, - "dependsOn": [ - "netAppAccount" + "backupPolicies", + "backupVaults", + "netAppAccount::capacityPool", + "snapshotPolicies" ] }, "backupVaults": { @@ -1508,7 +1481,8 @@ "name": "[format('{0}/{1}/{2}', parameters('netAppAccountName'), parameters('backupVaultName'), parameters('backupName'))]", "properties": "[if(parameters('backupEnabled'), createObject('label', parameters('backupLabel'), 'snapshotName', parameters('snapshotName'), 'useExistingSnapshot', parameters('useExistingSnapshot'), 'volumeResourceId', parameters('volumeResourceId')), createObject())]", "dependsOn": [ - "backupVaults" + "backupVaults", + "volume" ] }, "volume_roleAssignments": { @@ -1532,6 +1506,413 @@ "dependsOn": [ "volume" ] + }, + "backupPolicies": { + "condition": "[parameters('backupEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[parameters('backupPolicyName')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyBackupsToKeep": { + "value": "[parameters('dailyBackupsToKeep')]" + }, + "monthlyBackupsToKeep": { + "value": "[parameters('monthlyBackupsToKeep')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "weeklyBackupsToKeep": { + "value": "[parameters('weeklyBackupsToKeep')]" + }, + "backupEnabled": { + "value": "[parameters('backupEnabled')]" + }, + "backupPolicyLocation": { + "value": "[parameters('backupPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "16399924782439066553" + }, + "name": "Azure NetApp Files Backup Policy", + "description": "This module deploys a Backup Policy for Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "backupPolicyName": { + "type": "string", + "defaultValue": "backupPolicy", + "metadata": { + "description": "Required. The name of the backup policy." + } + }, + "backupPolicyLocation": { + "type": "string", + "metadata": { + "description": "Optional. The location of the backup policy. Required if the template is used in a standalone deployment." + } + }, + "dailyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The daily backups to keep." + } + }, + "monthlyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The monthly backups to keep." + } + }, + "weeklyBackupsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. The weekly backups to keep." + } + }, + "backupEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether the backup policy is enabled." + } + } + }, + "resources": [ + { + "type": "Microsoft.NetApp/netAppAccounts/backupPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('backupPolicyName'))]", + "location": "[parameters('backupPolicyLocation')]", + "properties": { + "dailyBackupsToKeep": "[parameters('dailyBackupsToKeep')]", + "enabled": "[parameters('backupEnabled')]", + "monthlyBackupsToKeep": "[parameters('monthlyBackupsToKeep')]", + "weeklyBackupsToKeep": "[parameters('weeklyBackupsToKeep')]" + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the backup Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/backupPolicies', parameters('netAppAccountName'), parameters('backupPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('backupPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Backup Policy was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } + }, + "snapshotPolicies": { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[uniqueString(parameters('snapshotPolicyName'))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "dailyHour": { + "value": "[parameters('dailyHour')]" + }, + "dailyMinute": { + "value": "[parameters('dailyMinute')]" + }, + "dailySnapshotsToKeep": { + "value": "[parameters('dailySnapshotsToKeep')]" + }, + "dailyUsedBytes": { + "value": "[parameters('dailyUsedBytes')]" + }, + "daysOfMonth": { + "value": "[parameters('daysOfMonth')]" + }, + "hourlyMinute": { + "value": "[parameters('hourlyMinute')]" + }, + "hourlySnapshotsToKeep": { + "value": "[parameters('hourlySnapshotsToKeep')]" + }, + "hourlyUsedBytes": { + "value": "[parameters('hourlyUsedBytes')]" + }, + "monthlyHour": { + "value": "[parameters('monthlyHour')]" + }, + "monthlyMinute": { + "value": "[parameters('monthlyMinute')]" + }, + "monthlySnapshotsToKeep": { + "value": "[parameters('monthlySnapshotsToKeep')]" + }, + "monthlyUsedBytes": { + "value": "[parameters('monthlyUsedBytes')]" + }, + "netAppAccountName": { + "value": "[parameters('netAppAccountName')]" + }, + "snapshotPolicyName": { + "value": "[parameters('snapshotPolicyName')]" + }, + "weeklyDay": { + "value": "[parameters('weeklyDay')]" + }, + "weeklyHour": { + "value": "[parameters('weeklyHour')]" + }, + "weeklyMinute": { + "value": "[parameters('weeklyMinute')]" + }, + "weeklySnapshotsToKeep": { + "value": "[parameters('weeklySnapshotsToKeep')]" + }, + "weeklyUsedBytes": { + "value": "[parameters('weeklyUsedBytes')]" + }, + "snapshotPolicyLocation": { + "value": "[parameters('snapshotPolicyLocation')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "17076752505050697613" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "dailyHour": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot hour." + } + }, + "dailyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot minute." + } + }, + "dailySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot count to keep." + } + }, + "dailyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot used bytes." + } + }, + "hourlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The hourly snapshot minute." + } + }, + "hourlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot count to keep." + } + }, + "hourlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot used bytes." + } + }, + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Optional. The monthly snapshot day." + } + }, + "monthlyHour": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot hour." + } + }, + "monthlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot minute." + } + }, + "monthlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot count to keep." + } + }, + "monthlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot used bytes." + } + }, + "weeklyDay": { + "type": "string", + "metadata": { + "description": "Optional. The weekly snapshot day." + } + }, + "weeklyHour": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot hour." + } + }, + "weeklyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot minute." + } + }, + "weeklySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot count to keep." + } + }, + "weeklyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot used bytes." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": [ + { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", + "location": "[parameters('snapshotPolicyLocation')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": { + "hour": "[parameters('dailyHour')]", + "minute": "[parameters('dailyMinute')]", + "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", + "usedBytes": "[parameters('dailyUsedBytes')]" + }, + "hourlySchedule": { + "minute": "[parameters('hourlyMinute')]", + "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", + "usedBytes": "[parameters('hourlyUsedBytes')]" + }, + "monthlySchedule": { + "daysOfMonth": "[parameters('daysOfMonth')]", + "hour": "[parameters('monthlyHour')]", + "minute": "[parameters('monthlyMinute')]", + "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", + "usedBytes": "[parameters('monthlyUsedBytes')]" + }, + "weeklySchedule": { + "day": "[parameters('weeklyDay')]", + "hour": "[parameters('weeklyHour')]", + "minute": "[parameters('weeklyMinute')]", + "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", + "usedBytes": "[parameters('weeklyUsedBytes')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the snapshot Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('snapshotPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Snapshot was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + } } }, "outputs": { diff --git a/avm/res/net-app/net-app-account/snapshot-policies/README.md b/avm/res/net-app/net-app-account/snapshot-policies/README.md new file mode 100644 index 0000000000..3fc4b313e2 --- /dev/null +++ b/avm/res/net-app/net-app-account/snapshot-policies/README.md @@ -0,0 +1,205 @@ +# Azure NetApp Files Snapshot Policy `[Microsoft.NetApp/netAppAccounts/snapshotPolicies]` + +This module deploys a Snapshot Policy for an Azure NetApp File. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.NetApp/netAppAccounts/snapshotPolicies` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.NetApp/2024-03-01/netAppAccounts/snapshotPolicies) | + +## Parameters + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`netAppAccountName`](#parameter-netappaccountname) | string | The name of the parent NetApp account. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`dailyHour`](#parameter-dailyhour) | int | The daily snapshot hour. | +| [`dailyMinute`](#parameter-dailyminute) | int | The daily snapshot minute. | +| [`dailySnapshotsToKeep`](#parameter-dailysnapshotstokeep) | int | Daily snapshot count to keep. | +| [`dailyUsedBytes`](#parameter-dailyusedbytes) | int | Daily snapshot used bytes. | +| [`daysOfMonth`](#parameter-daysofmonth) | string | The monthly snapshot day. | +| [`hourlyMinute`](#parameter-hourlyminute) | int | The hourly snapshot minute. | +| [`hourlySnapshotsToKeep`](#parameter-hourlysnapshotstokeep) | int | Hourly snapshot count to keep. | +| [`hourlyUsedBytes`](#parameter-hourlyusedbytes) | int | Hourly snapshot used bytes. | +| [`monthlyHour`](#parameter-monthlyhour) | int | The monthly snapshot hour. | +| [`monthlyMinute`](#parameter-monthlyminute) | int | The monthly snapshot minute. | +| [`monthlySnapshotsToKeep`](#parameter-monthlysnapshotstokeep) | int | Monthly snapshot count to keep. | +| [`monthlyUsedBytes`](#parameter-monthlyusedbytes) | int | Monthly snapshot used bytes. | +| [`snapEnabled`](#parameter-snapenabled) | bool | Indicates whether the snapshot policy is enabled. | +| [`snapshotPolicyLocation`](#parameter-snapshotpolicylocation) | string | The location of the snapshot policy. | +| [`snapshotPolicyName`](#parameter-snapshotpolicyname) | string | The name of the snapshot policy. | +| [`weeklyDay`](#parameter-weeklyday) | string | The weekly snapshot day. | +| [`weeklyHour`](#parameter-weeklyhour) | int | The weekly snapshot hour. | +| [`weeklyMinute`](#parameter-weeklyminute) | int | The weekly snapshot minute. | +| [`weeklySnapshotsToKeep`](#parameter-weeklysnapshotstokeep) | int | Weekly snapshot count to keep. | +| [`weeklyUsedBytes`](#parameter-weeklyusedbytes) | int | Weekly snapshot used bytes. | + +### Parameter: `netAppAccountName` + +The name of the parent NetApp account. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `dailyHour` + +The daily snapshot hour. + +- Required: Yes +- Type: int + +### Parameter: `dailyMinute` + +The daily snapshot minute. + +- Required: Yes +- Type: int + +### Parameter: `dailySnapshotsToKeep` + +Daily snapshot count to keep. + +- Required: Yes +- Type: int + +### Parameter: `dailyUsedBytes` + +Daily snapshot used bytes. + +- Required: Yes +- Type: int + +### Parameter: `daysOfMonth` + +The monthly snapshot day. + +- Required: Yes +- Type: string + +### Parameter: `hourlyMinute` + +The hourly snapshot minute. + +- Required: Yes +- Type: int + +### Parameter: `hourlySnapshotsToKeep` + +Hourly snapshot count to keep. + +- Required: Yes +- Type: int + +### Parameter: `hourlyUsedBytes` + +Hourly snapshot used bytes. + +- Required: Yes +- Type: int + +### Parameter: `monthlyHour` + +The monthly snapshot hour. + +- Required: Yes +- Type: int + +### Parameter: `monthlyMinute` + +The monthly snapshot minute. + +- Required: Yes +- Type: int + +### Parameter: `monthlySnapshotsToKeep` + +Monthly snapshot count to keep. + +- Required: Yes +- Type: int + +### Parameter: `monthlyUsedBytes` + +Monthly snapshot used bytes. + +- Required: Yes +- Type: int + +### Parameter: `snapEnabled` + +Indicates whether the snapshot policy is enabled. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `snapshotPolicyLocation` + +The location of the snapshot policy. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `snapshotPolicyName` + +The name of the snapshot policy. + +- Required: Yes +- Type: string + +### Parameter: `weeklyDay` + +The weekly snapshot day. + +- Required: Yes +- Type: string + +### Parameter: `weeklyHour` + +The weekly snapshot hour. + +- Required: Yes +- Type: int + +### Parameter: `weeklyMinute` + +The weekly snapshot minute. + +- Required: Yes +- Type: int + +### Parameter: `weeklySnapshotsToKeep` + +Weekly snapshot count to keep. + +- Required: Yes +- Type: int + +### Parameter: `weeklyUsedBytes` + +Weekly snapshot used bytes. + +- Required: Yes +- Type: int + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the Backup Policy. | +| `resourceGroupName` | string | The name of the Resource Group the Snapshot was created in. | +| `resourceId` | string | The resource IDs of the snapshot Policy created within volume. | diff --git a/avm/res/net-app/net-app-account/snapshot-policies/main.bicep b/avm/res/net-app/net-app-account/snapshot-policies/main.bicep new file mode 100644 index 0000000000..66eaca3163 --- /dev/null +++ b/avm/res/net-app/net-app-account/snapshot-policies/main.bicep @@ -0,0 +1,113 @@ +metadata name = 'Azure NetApp Files Snapshot Policy' +metadata description = 'This module deploys a Snapshot Policy for an Azure NetApp File.' +metadata owner = 'Azure/module-maintainers' + +@description('Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment.') +param netAppAccountName string + +@description('Optional. The name of the snapshot policy.') +param snapshotPolicyName string + +@description('Optional. The location of the snapshot policy.') +param snapshotPolicyLocation string = resourceGroup().location + +@description('Optional. The daily snapshot hour.') +param dailyHour int + +@description('Optional. The daily snapshot minute.') +param dailyMinute int + +@description('Optional. Daily snapshot count to keep.') +param dailySnapshotsToKeep int + +@description('Optional. Daily snapshot used bytes.') +param dailyUsedBytes int + +@description('Optional. The hourly snapshot minute.') +param hourlyMinute int + +@description('Optional. Hourly snapshot count to keep.') +param hourlySnapshotsToKeep int + +@description('Optional. Hourly snapshot used bytes.') +param hourlyUsedBytes int + +@description('Optional. The monthly snapshot day.') +param daysOfMonth string + +@description('Optional. The monthly snapshot hour.') +param monthlyHour int + +@description('Optional. The monthly snapshot minute.') +param monthlyMinute int + +@description('Optional. Monthly snapshot count to keep.') +param monthlySnapshotsToKeep int + +@description('Optional. Monthly snapshot used bytes.') +param monthlyUsedBytes int + +@description('Optional. The weekly snapshot day.') +param weeklyDay string + +@description('Optional. The weekly snapshot hour.') +param weeklyHour int + +@description('Optional. The weekly snapshot minute.') +param weeklyMinute int + +@description('Optional. Weekly snapshot count to keep.') +param weeklySnapshotsToKeep int + +@description('Optional. Weekly snapshot used bytes.') +param weeklyUsedBytes int + +@description('Optional. Indicates whether the snapshot policy is enabled.') +param snapEnabled bool = true + +resource netAppAccount 'Microsoft.NetApp/netAppAccounts@2024-03-01' existing = { + name: netAppAccountName +} + +resource snapshotPolicies 'Microsoft.NetApp/netAppAccounts/snapshotPolicies@2024-03-01' = if (snapEnabled) { + name: snapshotPolicyName + parent: netAppAccount + location: snapshotPolicyLocation + properties: { + enabled: snapEnabled + dailySchedule: { + hour: dailyHour + minute: dailyMinute + snapshotsToKeep: dailySnapshotsToKeep + usedBytes: dailyUsedBytes + } + hourlySchedule: { + minute: hourlyMinute + snapshotsToKeep: hourlySnapshotsToKeep + usedBytes: hourlyUsedBytes + } + monthlySchedule: { + daysOfMonth: daysOfMonth + hour: monthlyHour + minute: monthlyMinute + snapshotsToKeep: monthlySnapshotsToKeep + usedBytes: monthlyUsedBytes + } + weeklySchedule: { + day: weeklyDay + hour: weeklyHour + minute: weeklyMinute + snapshotsToKeep: weeklySnapshotsToKeep + usedBytes: weeklyUsedBytes + } + } +} + +@description('The resource IDs of the snapshot Policy created within volume.') +output resourceId string = snapshotPolicies.id + +@description('The name of the Backup Policy.') +output name string = snapshotPolicies.name + +@description('The name of the Resource Group the Snapshot was created in.') +output resourceGroupName string = resourceGroup().name diff --git a/avm/res/net-app/net-app-account/snapshot-policies/main.json b/avm/res/net-app/net-app-account/snapshot-policies/main.json new file mode 100644 index 0000000000..d92af406dd --- /dev/null +++ b/avm/res/net-app/net-app-account/snapshot-policies/main.json @@ -0,0 +1,204 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.3.12046", + "templateHash": "17076752505050697613" + }, + "name": "Azure NetApp Files Snapshot Policy", + "description": "This module deploys a Snapshot Policy for an Azure NetApp File.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "netAppAccountName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent NetApp account. Required if the template is used in a standalone deployment." + } + }, + "snapshotPolicyName": { + "type": "string", + "metadata": { + "description": "Optional. The name of the snapshot policy." + } + }, + "snapshotPolicyLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. The location of the snapshot policy." + } + }, + "dailyHour": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot hour." + } + }, + "dailyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The daily snapshot minute." + } + }, + "dailySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot count to keep." + } + }, + "dailyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Daily snapshot used bytes." + } + }, + "hourlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The hourly snapshot minute." + } + }, + "hourlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot count to keep." + } + }, + "hourlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Hourly snapshot used bytes." + } + }, + "daysOfMonth": { + "type": "string", + "metadata": { + "description": "Optional. The monthly snapshot day." + } + }, + "monthlyHour": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot hour." + } + }, + "monthlyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The monthly snapshot minute." + } + }, + "monthlySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot count to keep." + } + }, + "monthlyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Monthly snapshot used bytes." + } + }, + "weeklyDay": { + "type": "string", + "metadata": { + "description": "Optional. The weekly snapshot day." + } + }, + "weeklyHour": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot hour." + } + }, + "weeklyMinute": { + "type": "int", + "metadata": { + "description": "Optional. The weekly snapshot minute." + } + }, + "weeklySnapshotsToKeep": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot count to keep." + } + }, + "weeklyUsedBytes": { + "type": "int", + "metadata": { + "description": "Optional. Weekly snapshot used bytes." + } + }, + "snapEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates whether the snapshot policy is enabled." + } + } + }, + "resources": [ + { + "condition": "[parameters('snapEnabled')]", + "type": "Microsoft.NetApp/netAppAccounts/snapshotPolicies", + "apiVersion": "2024-03-01", + "name": "[format('{0}/{1}', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]", + "location": "[parameters('snapshotPolicyLocation')]", + "properties": { + "enabled": "[parameters('snapEnabled')]", + "dailySchedule": { + "hour": "[parameters('dailyHour')]", + "minute": "[parameters('dailyMinute')]", + "snapshotsToKeep": "[parameters('dailySnapshotsToKeep')]", + "usedBytes": "[parameters('dailyUsedBytes')]" + }, + "hourlySchedule": { + "minute": "[parameters('hourlyMinute')]", + "snapshotsToKeep": "[parameters('hourlySnapshotsToKeep')]", + "usedBytes": "[parameters('hourlyUsedBytes')]" + }, + "monthlySchedule": { + "daysOfMonth": "[parameters('daysOfMonth')]", + "hour": "[parameters('monthlyHour')]", + "minute": "[parameters('monthlyMinute')]", + "snapshotsToKeep": "[parameters('monthlySnapshotsToKeep')]", + "usedBytes": "[parameters('monthlyUsedBytes')]" + }, + "weeklySchedule": { + "day": "[parameters('weeklyDay')]", + "hour": "[parameters('weeklyHour')]", + "minute": "[parameters('weeklyMinute')]", + "snapshotsToKeep": "[parameters('weeklySnapshotsToKeep')]", + "usedBytes": "[parameters('weeklyUsedBytes')]" + } + } + } + ], + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource IDs of the snapshot Policy created within volume." + }, + "value": "[resourceId('Microsoft.NetApp/netAppAccounts/snapshotPolicies', parameters('netAppAccountName'), parameters('snapshotPolicyName'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Backup Policy." + }, + "value": "[parameters('snapshotPolicyName')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Resource Group the Snapshot was created in." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file From 59622847d81ef197322b5f57d21e5ce49d8f54eb Mon Sep 17 00:00:00 2001 From: Elena Batanero <46710322+elbatane@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:36:48 +0200 Subject: [PATCH 07/17] docs: ORPHANED Vnet Module (#3492) ## Description VNET module Orphaned ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.network.virtual-network](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml/badge.svg?branch=users%2Felbatane%2Fvnet_orphan)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.network.virtual-network.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [X] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --------- Co-authored-by: Elena Batanero Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- avm/res/network/virtual-network/ORPHANED.md | 4 ++++ avm/res/network/virtual-network/README.md | 5 +++++ 2 files changed, 9 insertions(+) create mode 100644 avm/res/network/virtual-network/ORPHANED.md diff --git a/avm/res/network/virtual-network/ORPHANED.md b/avm/res/network/virtual-network/ORPHANED.md new file mode 100644 index 0000000000..ef8fa911d2 --- /dev/null +++ b/avm/res/network/virtual-network/ORPHANED.md @@ -0,0 +1,4 @@ +⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ + +- Only security and bug fixes are being handled by the AVM core team at present. +- If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! \ No newline at end of file diff --git a/avm/res/network/virtual-network/README.md b/avm/res/network/virtual-network/README.md index c61cf59589..02339df598 100644 --- a/avm/res/network/virtual-network/README.md +++ b/avm/res/network/virtual-network/README.md @@ -1,5 +1,10 @@ # Virtual Networks `[Microsoft.Network/virtualNetworks]` +> ⚠️THIS MODULE IS CURRENTLY ORPHANED.⚠️ +> +> - Only security and bug fixes are being handled by the AVM core team at present. +> - If interested in becoming the module owner of this orphaned module (must be Microsoft FTE), please look for the related "orphaned module" GitHub issue [here](https://aka.ms/AVM/OrphanedModules)! + This module deploys a Virtual Network (vNet). ## Navigation From dda478de2e74c32fc4eb9049de47edc60777f2d2 Mon Sep 17 00:00:00 2001 From: "Menghua Chen (MSFT)" <111940661+Menghua1@users.noreply.github.com> Date: Fri, 11 Oct 2024 15:38:54 +0800 Subject: [PATCH 08/17] feat: Add new ptn modules `avm/ptn/azd/ml-project`. (#3244) ## Description Fixes https://github.com/Azure/Azure-Verified-Modules/issues/1228. ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.ml-project](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml/badge.svg)](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .github/workflows/avm.ptn.azd.ml-project.yml | 88 + avm/ptn/azd/ml-project/README.md | 333 + avm/ptn/azd/ml-project/main.bicep | 174 + avm/ptn/azd/ml-project/main.json | 7436 +++++++++++++++++ .../tests/e2e/defaults/dependencies.bicep | 60 + .../tests/e2e/defaults/main.test.bicep | 61 + avm/ptn/azd/ml-project/version.json | 7 + 9 files changed, 8161 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.ml-project.yml create mode 100644 avm/ptn/azd/ml-project/README.md create mode 100644 avm/ptn/azd/ml-project/main.bicep create mode 100644 avm/ptn/azd/ml-project/main.json create mode 100644 avm/ptn/azd/ml-project/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/ptn/azd/ml-project/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/ml-project/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 2167ffc054..73abc09b92 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -16,6 +16,7 @@ /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/ml-project/ @Azure/avm-ptn-azd-mlproject-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/ml-hub-dependencies/ @Azure/avm-ptn-azd-mlhubdependencies-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/monitoring/ @Azure/avm-ptn-azd-monitoring-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/deployment-script/import-image-to-acr/ @Azure/avm-ptn-deploymentscript-importimagetoacr-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index a74c246995..719a8c2982 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -51,6 +51,7 @@ body: - "avm/ptn/azd/apim-api" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" + - "avm/ptn/azd/ml-project" - "avm/ptn/azd/ml-hub-dependencies" - "avm/ptn/azd/monitoring" - "avm/ptn/deployment-script/import-image-to-acr" diff --git a/.github/workflows/avm.ptn.azd.ml-project.yml b/.github/workflows/avm.ptn.azd.ml-project.yml new file mode 100644 index 0000000000..b2d2f60191 --- /dev/null +++ b/.github/workflows/avm.ptn.azd.ml-project.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.ml-project" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.ml-project" + - "avm/ptn/azd/ml-project/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/ml-project" + workflowPath: ".github/workflows/avm.ptn.azd.ml-project.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit \ No newline at end of file diff --git a/avm/ptn/azd/ml-project/README.md b/avm/ptn/azd/ml-project/README.md new file mode 100644 index 0000000000..dc07753fe1 --- /dev/null +++ b/avm/ptn/azd/ml-project/README.md @@ -0,0 +1,333 @@ +# Azd Machine Learning workspace `[Azd/MlProject]` + +Create a machine learning workspace, configure the key vault access policy and assign role permissions to the machine learning instance. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.KeyVault/vaults` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults) | +| `Microsoft.KeyVault/vaults/accessPolicies` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/accessPolicies) | +| `Microsoft.KeyVault/vaults/keys` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/keys) | +| `Microsoft.KeyVault/vaults/secrets` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/secrets) | +| `Microsoft.MachineLearningServices/workspaces` | [2024-04-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2024-04-01-preview/workspaces) | +| `Microsoft.MachineLearningServices/workspaces/computes` | [2022-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2022-10-01/workspaces/computes) | +| `Microsoft.MachineLearningServices/workspaces/connections` | [2024-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.MachineLearningServices/2024-04-01/workspaces/connections) | +| `Microsoft.ManagedIdentity/userAssignedIdentities` | [2023-01-31](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ManagedIdentity/2023-01-31/userAssignedIdentities) | +| `Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials` | [2023-01-31](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ManagedIdentity/2023-01-31/userAssignedIdentities/federatedIdentityCredentials) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/azd/ml-project:`. + +- [Using only defaults](#example-1-using-only-defaults) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module mlProject 'br/public:avm/ptn/azd/ml-project:' = { + name: 'mlProjectDeployment' + params: { + // Required parameters + hubResourceId: '' + keyVaultName: '' + name: 'mlpmin001' + userAssignedName: 'mlpminuai001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "hubResourceId": { + "value": "" + }, + "keyVaultName": { + "value": "" + }, + "name": { + "value": "mlpmin001" + }, + "userAssignedName": { + "value": "mlpminuai001" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/ml-project:' + +// Required parameters +param hubResourceId = '' +param keyVaultName = '' +param name = 'mlpmin001' +param userAssignedName = 'mlpminuai001' +// Non-required parameters +param location = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`hubResourceId`](#parameter-hubresourceid) | string | The resource ID of the AI Studio Hub Resource where this project should be created. | +| [`keyVaultName`](#parameter-keyvaultname) | string | The name of the key vault. | +| [`name`](#parameter-name) | string | The name of the machine learning workspace. | +| [`userAssignedName`](#parameter-userassignedname) | string | The name of the user assigned identity. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`hbiWorkspace`](#parameter-hbiworkspace) | bool | The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`projectKind`](#parameter-projectkind) | string | The type of Azure Machine Learning workspace to create. | +| [`projectManagedIdentities`](#parameter-projectmanagedidentities) | object | The managed identity definition for the machine learning resource. At least one identity type is required. | +| [`projectSku`](#parameter-projectsku) | string | Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled. | +| [`roleDefinitionIdOrName`](#parameter-roledefinitionidorname) | array | 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'. Default roles: AzureML Data Scientist, Azure Machine Learning Workspace Connection Secrets Reader. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | + +### Parameter: `hubResourceId` + +The resource ID of the AI Studio Hub Resource where this project should be created. + +- Required: Yes +- Type: string + +### Parameter: `keyVaultName` + +The name of the key vault. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the machine learning workspace. + +- Required: Yes +- Type: string + +### Parameter: `userAssignedName` + +The name of the user assigned identity. + +- Required: Yes +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `hbiWorkspace` + +The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `projectKind` + +The type of Azure Machine Learning workspace to create. + +- Required: No +- Type: string +- Default: `'Project'` +- Allowed: + ```Bicep + [ + 'Default' + 'FeatureStore' + 'Hub' + 'Project' + ] + ``` + +### Parameter: `projectManagedIdentities` + +The managed identity definition for the machine learning resource. At least one identity type is required. + +- Required: No +- Type: object +- Default: + ```Bicep + { + systemAssigned: true + } + ``` + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`systemAssigned`](#parameter-projectmanagedidentitiessystemassigned) | bool | Enables system assigned managed identity on the resource. Must be false if `primaryUserAssignedIdentity` is provided. | +| [`userAssignedResourceIds`](#parameter-projectmanagedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. | + +### Parameter: `projectManagedIdentities.systemAssigned` + +Enables system assigned managed identity on the resource. Must be false if `primaryUserAssignedIdentity` is provided. + +- Required: No +- Type: bool + +### Parameter: `projectManagedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. + +- Required: No +- Type: array + +### Parameter: `projectSku` + +Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace. + +- Required: No +- Type: string +- Default: `'Basic'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Free' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `publicNetworkAccess` + +Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. Default roles: AzureML Data Scientist, Azure Machine Learning Workspace Connection Secrets Reader. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 'ea01e6af-a1c1-4350-9563-ad00f8c72ec5' + 'f6c7c914-8db3-469d-8ca1-694a8f32e121' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object +- Example: + ```Bicep + { + "key1": "value1" + "key2": "value2" + } + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `projectName` | string | The resource name of the machine learning workspace. | +| `projectPrincipalId` | string | The principal ID of the machine learning workspace. | +| `projectResourceId` | string | The resource ID of the machine learning workspace. | +| `resourceGroupName` | string | The resource group the machine learning workspace were deployed into. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/key-vault/vault:0.9.0` | Remote reference | +| `br/public:avm/res/machine-learning-services/workspace:0.7.0` | Remote reference | +| `br/public:avm/res/managed-identity/user-assigned-identity:0.4.0` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/ptn/azd/ml-project/main.bicep b/avm/ptn/azd/ml-project/main.bicep new file mode 100644 index 0000000000..effc6771d5 --- /dev/null +++ b/avm/ptn/azd/ml-project/main.bicep @@ -0,0 +1,174 @@ +metadata name = 'Azd Machine Learning workspace' +metadata description = '''Create a machine learning workspace, configure the key vault access policy and assign role permissions to the machine learning instance. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the machine learning workspace.') +param name string + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +@metadata({ + example: ''' + { + "key1": "value1" + "key2": "value2" + } + ''' +}) +param tags object? + +@description('Optional. Specifies the SKU, also referred as \'edition\' of the Azure Machine Learning workspace.') +@allowed([ + 'Free' + 'Basic' + 'Standard' + 'Premium' +]) +param projectSku string = 'Basic' + +@description('Optional. The type of Azure Machine Learning workspace to create.') +@allowed([ + 'Default' + 'Project' + 'Hub' + 'FeatureStore' +]) +param projectKind string = 'Project' + +@description('Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service.') +param hbiWorkspace bool = false + +@description('Optional. Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = 'Enabled' + +@description('Required. The resource ID of the AI Studio Hub Resource where this project should be created.') +param hubResourceId string + +@description('Required. The name of the key vault.') +param keyVaultName string + +@description('Optional. The managed identity definition for the machine learning resource. At least one identity type is required.') +param projectManagedIdentities managedIdentitiesType = { + systemAssigned: true +} + +@description('Required. The name of the user assigned identity.') +param userAssignedName string + +@description('Optional. 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\'. Default roles: AzureML Data Scientist, Azure Machine Learning Workspace Connection Secrets Reader.') +param roleDefinitionIdOrName array = [ + 'f6c7c914-8db3-469d-8ca1-694a8f32e121' // AzureML Data Scientist + 'ea01e6af-a1c1-4350-9563-ad00f8c72ec5' // Azure Machine Learning Workspace Connection Secrets Reader +] + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.azd-mlproject.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +module project 'br/public:avm/res/machine-learning-services/workspace:0.7.0' = { + name: '${uniqueString(deployment().name, location)}-project' + params: { + name: name + tags: tags + sku: projectSku + kind: projectKind + managedIdentities: projectManagedIdentities + hbiWorkspace: hbiWorkspace + publicNetworkAccess: publicNetworkAccess + hubResourceId: hubResourceId + enableTelemetry: enableTelemetry + } +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +module keyVaultAccess 'br/public:avm/res/key-vault/vault:0.9.0' = { + name: '${uniqueString(deployment().name, location)}-keyvault' + params: { + name: keyVault.name + accessPolicies: [ + { + objectId: project.outputs.systemAssignedMIPrincipalId + permissions: { secrets: [ 'get', 'list' ] } + } + ] + enableTelemetry: enableTelemetry + } +} + +module mlServiceRoleAssigned 'br/public:avm/res/managed-identity/user-assigned-identity:0.4.0' = { + name: '${uniqueString(deployment().name, location)}-roleassignment' + params: { + name: userAssignedName + location: location + roleAssignments: [ + for id in roleDefinitionIdOrName: { + principalId: project.outputs.systemAssignedMIPrincipalId + roleDefinitionIdOrName: id + principalType: 'ServicePrincipal' + } + ] + enableTelemetry: enableTelemetry + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The resource group the machine learning workspace were deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the machine learning workspace.') +output projectResourceId string = project.outputs.resourceId + +@description('The resource name of the machine learning workspace.') +output projectName string = project.outputs.name + +@description('The principal ID of the machine learning workspace.') +output projectPrincipalId string = project.outputs.systemAssignedMIPrincipalId + +// =============== // +// Definitions // +// =============== // + +type managedIdentitiesType = { + @description('Optional. Enables system assigned managed identity on the resource. Must be false if `primaryUserAssignedIdentity` is provided.') + systemAssigned: bool? + + @description('Optional. The resource ID(s) to assign to the resource.') + userAssignedResourceIds: string[]? +} + diff --git a/avm/ptn/azd/ml-project/main.json b/avm/ptn/azd/ml-project/main.json new file mode 100644 index 0000000000..01d5610330 --- /dev/null +++ b/avm/ptn/azd/ml-project/main.json @@ -0,0 +1,7436 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "12979908494001456774" + }, + "name": "Azd Machine Learning workspace", + "description": "Create a machine learning workspace, configure the key vault access policy and assign role permissions to the machine learning instance.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource. Must be false if `primaryUserAssignedIdentity` is provided." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the machine learning workspace." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "example": " {\n \"key1\": \"value1\"\n \"key2\": \"value2\"\n }\n ", + "description": "Optional. Tags of the resource." + } + }, + "projectSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Free", + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "Optional. Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace." + } + }, + "projectKind": { + "type": "string", + "defaultValue": "Project", + "allowedValues": [ + "Default", + "Project", + "Hub", + "FeatureStore" + ], + "metadata": { + "description": "Optional. The type of Azure Machine Learning workspace to create." + } + }, + "hbiWorkspace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled." + } + }, + "hubResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the AI Studio Hub Resource where this project should be created." + } + }, + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Required. The name of the key vault." + } + }, + "projectManagedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "defaultValue": { + "systemAssigned": true + }, + "metadata": { + "description": "Optional. The managed identity definition for the machine learning resource. At least one identity type is required." + } + }, + "userAssignedName": { + "type": "string", + "metadata": { + "description": "Required. The name of the user assigned identity." + } + }, + "roleDefinitionIdOrName": { + "type": "array", + "defaultValue": [ + "f6c7c914-8db3-469d-8ca1-694a8f32e121", + "ea01e6af-a1c1-4350-9563-ad00f8c72ec5" + ], + "metadata": { + "description": "Optional. 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'. Default roles: AzureML Data Scientist, Azure Machine Learning Workspace Connection Secrets Reader." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-mlproject.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "project": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-project', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "sku": { + "value": "[parameters('projectSku')]" + }, + "kind": { + "value": "[parameters('projectKind')]" + }, + "managedIdentities": { + "value": "[parameters('projectManagedIdentities')]" + }, + "hbiWorkspace": { + "value": "[parameters('hbiWorkspace')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "hubResourceId": { + "value": "[parameters('hubResourceId')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "8914196510655371542" + }, + "name": "Machine Learning Services Workspaces", + "description": "This module deploys a Machine Learning Services Workspace.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource. Must be false if `primaryUserAssignedIdentity` is provided." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + } + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroup": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "featureStoreSettingType": { + "type": "object", + "properties": { + "computeRuntime": { + "type": "object", + "properties": { + "sparkRuntimeVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The spark runtime version." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Compute runtime config for feature store type workspace." + } + }, + "offlineStoreConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The offline store connection name." + } + }, + "onlineStoreConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The online store connection name." + } + } + }, + "nullable": true + }, + "OutboundRuleType": { + "type": "object", + "discriminator": { + "propertyName": "type", + "mapping": { + "FQDN": { + "$ref": "#/definitions/FqdnOutboundRuleType" + }, + "PrivateEndpoint": { + "$ref": "#/definitions/PrivateEndpointOutboundRule" + }, + "ServiceTag": { + "$ref": "#/definitions/ServiceTagOutboundRule" + } + } + } + }, + "FqdnOutboundRuleType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "FQDN" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound'." + } + }, + "destination": { + "type": "string", + "metadata": { + "description": "Required. Fully Qualified Domain Name to allow for outbound traffic." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "PrivateEndpointOutboundRule": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "PrivateEndpoint" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound' or 'AllowInternetOutbound'." + } + }, + "destination": { + "type": "object", + "properties": { + "serviceResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the target resource for the private endpoint." + } + }, + "sparkEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether the private endpoint can be used by jobs running on Spark." + } + }, + "subresourceTarget": { + "type": "string", + "metadata": { + "description": "Required. The sub resource to connect for the private endpoint." + } + } + }, + "metadata": { + "description": "Required. Service Tag destination for a Service Tag Outbound Rule for the managed network of a machine learning workspace." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "ServiceTagOutboundRule": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "ServiceTag" + ], + "metadata": { + "description": "Required. Type of a managed network Outbound Rule of a machine learning workspace. Only supported when 'isolationMode' is 'AllowOnlyApprovedOutbound'." + } + }, + "destination": { + "type": "object", + "properties": { + "portRanges": { + "type": "string", + "metadata": { + "description": "Required. The name of the service tag to allow." + } + }, + "protocol": { + "type": "string", + "allowedValues": [ + "*", + "ICMP", + "TCP", + "UDP" + ], + "metadata": { + "description": "Required. The protocol to allow. Provide an asterisk(*) to allow any protocol." + } + }, + "serviceTag": { + "type": "string", + "metadata": { + "description": "Required. Which ports will be allow traffic by this rule. Provide an asterisk(*) to allow any port." + } + } + }, + "metadata": { + "description": "Required. Service Tag destination for a Service Tag Outbound Rule for the managed network of a machine learning workspace." + } + }, + "category": { + "type": "string", + "allowedValues": [ + "Dependency", + "Recommended", + "Required", + "UserDefined" + ], + "nullable": true, + "metadata": { + "description": "Optional. Category of a managed network Outbound Rule of a machine learning workspace." + } + } + } + }, + "managedNetworkSettingType": { + "type": "object", + "properties": { + "isolationMode": { + "type": "string", + "allowedValues": [ + "AllowInternetOutbound", + "AllowOnlyApprovedOutbound", + "Disabled" + ], + "metadata": { + "description": "Required. Isolation mode for the managed network of a machine learning workspace." + } + }, + "outboundRules": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/OutboundRuleType", + "metadata": { + "description": "Required. The outbound rule. The name of the rule is the object key." + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Outbound rules for the managed network of a machine learning workspace." + } + } + }, + "nullable": true + }, + "serverlessComputeSettingType": { + "type": "object", + "properties": { + "serverlessComputeCustomSubnet": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of an existing virtual network subnet in which serverless compute nodes should be deployed." + } + }, + "serverlessComputeNoPublicIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The flag to signal if serverless compute nodes deployed in custom vNet would have no public IP addresses for a workspace with private endpoint." + } + } + }, + "nullable": true + }, + "workspaceHubConfigType": { + "type": "object", + "properties": { + "additionalWorkspaceStorageAccounts": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource IDs of additional storage accounts to attach to the workspace." + } + }, + "defaultWorkspaceResourceGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the default resource group for projects created in the workspace hub." + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + }, + "connectionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the connection to create." + } + }, + "category": { + "$ref": "#/definitions/categoryType", + "metadata": { + "description": "Required. Category of the connection." + } + }, + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiry time of the connection." + } + }, + "isSharedToAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the connection is shared to all users in the workspace." + } + }, + "metadata": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. The metadata key-value pairs." + } + }, + "nullable": true, + "metadata": { + "description": "Optional. User metadata for the connection." + } + }, + "sharedUserList": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The shared user list of the connection." + } + }, + "target": { + "type": "string", + "metadata": { + "description": "Required. The target of the connection." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Value details of the workspace connection." + } + }, + "connectionProperties": { + "$ref": "#/definitions/connectionPropertyType", + "metadata": { + "description": "Required. The properties of the connection, specific to the auth type." + } + } + } + }, + "_1.aadAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AAD" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.accessKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccessKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionAccessKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.apiKeyAuthWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ApiKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionApiKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.customKeysType": { + "type": "object", + "properties": { + "keys": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. Key-value pairs for the custom keys." + } + }, + "metadata": { + "description": "Required. The custom keys for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.customKeysWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "CustomKeys" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.customKeysType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.managedIdentityAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ManagedIdentity" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionManagedIdentityType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.noneAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "None" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.oauth2AuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "OAuth2" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionOAuth2Type", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.patAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "PAT" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionPersonalAccessTokenType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.sasAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "SAS" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionSharedAccessSignatureType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.servicePrincipalAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionServicePrincipalType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.usernamePasswordAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "UsernamePassword" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/_1.workspaceConnectionUsernamePasswordType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionAccessKeyType": { + "type": "object", + "properties": { + "accessKeyId": { + "type": "string", + "metadata": { + "description": "Required. The connection access key ID." + } + }, + "secretAccessKey": { + "type": "string", + "metadata": { + "description": "Required. The connection secret access key." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionApiKeyType": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection API key." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionManagedIdentityType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity ID." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity resource ID." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionOAuth2Type": { + "type": "object", + "properties": { + "authUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection auth URL. Required by Concur connection category." + } + }, + "clientId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "Required. The connection client ID in the format of UUID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "developerToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection developer token. Required by GoogleAdWords connection category." + } + }, + "password": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection password. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + }, + "refreshToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection refresh token. Required by GoogleBigQuery, GoogleAdWords, Hubspot, QuickBooks, Square, Xero and Zoho connection categories." + } + }, + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The connection tenant ID. Required by QuickBooks and Xero connection categories." + } + }, + "username": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection username. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionPersonalAccessTokenType": { + "type": "object", + "properties": { + "pat": { + "type": "string", + "metadata": { + "description": "Required. The connection personal access token." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionServicePrincipalType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection client ID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The connection tenant ID." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionSharedAccessSignatureType": { + "type": "object", + "properties": { + "sas": { + "type": "string", + "metadata": { + "description": "Required. The connection SAS token." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "_1.workspaceConnectionUsernamePasswordType": { + "type": "object", + "properties": { + "password": { + "type": "string", + "metadata": { + "description": "Required. The connection password." + } + }, + "securityToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection security token. Required by connections like SalesForce for extra security in addition to 'UsernamePassword'." + } + }, + "username": { + "type": "string", + "metadata": { + "description": "Required. The connection username." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "categoryType": { + "type": "string", + "allowedValues": [ + "ADLSGen2", + "AIServices", + "AmazonMws", + "AmazonRdsForOracle", + "AmazonRdsForSqlServer", + "AmazonRedshift", + "AmazonS3Compatible", + "ApiKey", + "AzureBlob", + "AzureDataExplorer", + "AzureDatabricksDeltaLake", + "AzureMariaDb", + "AzureMySqlDb", + "AzureOneLake", + "AzureOpenAI", + "AzurePostgresDb", + "AzureSqlDb", + "AzureSqlMi", + "AzureSynapseAnalytics", + "AzureTableStorage", + "BingLLMSearch", + "Cassandra", + "CognitiveSearch", + "CognitiveService", + "Concur", + "ContainerRegistry", + "CosmosDb", + "CosmosDbMongoDbApi", + "Couchbase", + "CustomKeys", + "Db2", + "Drill", + "Dynamics", + "DynamicsAx", + "DynamicsCrm", + "Eloqua", + "FileServer", + "FtpServer", + "GenericContainerRegistry", + "GenericHttp", + "GenericRest", + "Git", + "GoogleAdWords", + "GoogleBigQuery", + "GoogleCloudStorage", + "Greenplum", + "Hbase", + "Hdfs", + "Hive", + "Hubspot", + "Impala", + "Informix", + "Jira", + "Magento", + "MariaDb", + "Marketo", + "MicrosoftAccess", + "MongoDbAtlas", + "MongoDbV2", + "MySql", + "Netezza", + "ODataRest", + "Odbc", + "Office365", + "OpenAI", + "Oracle", + "OracleCloudStorage", + "OracleServiceCloud", + "PayPal", + "Phoenix", + "PostgreSql", + "Presto", + "PythonFeed", + "QuickBooks", + "Redis", + "Responsys", + "S3", + "Salesforce", + "SalesforceMarketingCloud", + "SalesforceServiceCloud", + "SapBw", + "SapCloudForCustomer", + "SapEcc", + "SapHana", + "SapOpenHub", + "SapTable", + "Serp", + "Serverless", + "ServiceNow", + "Sftp", + "SharePointOnlineList", + "Shopify", + "Snowflake", + "Spark", + "SqlServer", + "Square", + "Sybase", + "Teradata", + "Vertica", + "WebTable", + "Xero", + "Zoho" + ], + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + }, + "connectionPropertyType": { + "type": "secureObject", + "discriminator": { + "propertyName": "authType", + "mapping": { + "AAD": { + "$ref": "#/definitions/_1.aadAuthTypeWorkspaceConnectionPropertyType" + }, + "AccessKey": { + "$ref": "#/definitions/_1.accessKeyAuthTypeWorkspaceConnectionPropertyType" + }, + "ApiKey": { + "$ref": "#/definitions/_1.apiKeyAuthWorkspaceConnectionPropertyType" + }, + "CustomKeys": { + "$ref": "#/definitions/_1.customKeysWorkspaceConnectionPropertyType" + }, + "ManagedIdentity": { + "$ref": "#/definitions/_1.managedIdentityAuthTypeWorkspaceConnectionPropertyType" + }, + "None": { + "$ref": "#/definitions/_1.noneAuthTypeWorkspaceConnectionPropertyType" + }, + "OAuth2": { + "$ref": "#/definitions/_1.oauth2AuthTypeWorkspaceConnectionPropertyType" + }, + "PAT": { + "$ref": "#/definitions/_1.patAuthTypeWorkspaceConnectionPropertyType" + }, + "SAS": { + "$ref": "#/definitions/_1.sasAuthTypeWorkspaceConnectionPropertyType" + }, + "ServicePrincipal": { + "$ref": "#/definitions/_1.servicePrincipalAuthTypeWorkspaceConnectionPropertyType" + }, + "UsernamePassword": { + "$ref": "#/definitions/_1.usernamePasswordAuthTypeWorkspaceConnectionPropertyType" + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "connection/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the machine learning workspace." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "sku": { + "type": "string", + "allowedValues": [ + "Free", + "Basic", + "Standard", + "Premium" + ], + "metadata": { + "description": "Required. Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace." + } + }, + "kind": { + "type": "string", + "defaultValue": "Default", + "allowedValues": [ + "Default", + "Project", + "Hub", + "FeatureStore" + ], + "metadata": { + "description": "Optional. The type of Azure Machine Learning workspace to create." + } + }, + "associatedStorageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Storage Account. Required if 'kind' is 'Default', 'FeatureStore' or 'Hub'." + } + }, + "associatedKeyVaultResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Key Vault. Required if 'kind' is 'Default', 'FeatureStore' or 'Hub'." + } + }, + "associatedApplicationInsightsResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the associated Application Insights. Required if 'kind' is 'Default' or 'FeatureStore'." + } + }, + "associatedContainerRegistryResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the associated Container Registry." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "hbiWorkspace": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service." + } + }, + "hubResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The resource ID of the hub to associate with the workspace. Required if 'kind' is set to 'Project'." + } + }, + "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." + } + }, + "computes": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Computes to create respectively attach to the workspace." + } + }, + "connections": { + "type": "array", + "items": { + "$ref": "#/definitions/connectionType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Connections to create in the workspace." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "defaultValue": { + "systemAssigned": true + }, + "metadata": { + "description": "Optional. The managed identity definition for this resource. At least one identity type is required." + } + }, + "featureStoreSettings": { + "$ref": "#/definitions/featureStoreSettingType", + "metadata": { + "description": "Conditional. Settings for feature store type workspaces. Required if 'kind' is set to 'FeatureStore'." + } + }, + "managedNetworkSettings": { + "$ref": "#/definitions/managedNetworkSettingType", + "metadata": { + "description": "Optional. Managed Network settings for a machine learning workspace." + } + }, + "serverlessComputeSettings": { + "$ref": "#/definitions/serverlessComputeSettingType", + "metadata": { + "description": "Optional. Settings for serverless compute created in the workspace." + } + }, + "systemDatastoresAuthMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "accessKey", + "identity" + ], + "metadata": { + "description": "Optional. The authentication mode used by the workspace when connecting to the default storage account." + } + }, + "workspaceHubConfig": { + "$ref": "#/definitions/workspaceHubConfigType", + "metadata": { + "description": "Optional. Configuration for workspace hub settings." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of this workspace." + } + }, + "discoveryUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. URL for the discovery service to identify regional endpoints for machine learning experimentation services." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "imageBuildCompute": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The compute name for image build." + } + }, + "primaryUserAssignedIdentity": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The user assigned identity resource ID that represents the workspace identity. Required if 'userAssignedIdentities' is not empty and may not be used if 'systemAssignedIdentity' is enabled." + } + }, + "serviceManagedResourcesSettings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The service managed resource settings." + } + }, + "sharedPrivateLinkResources": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of shared private link resources in this workspace. Note: This property is not idempotent." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "AzureML Compute Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e503ece1-11d0-4e8e-8e2c-7a6c3bf38815')]", + "AzureML Data Scientist": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f6c7c914-8db3-469d-8ca1-694a8f32e121')]", + "AzureML Metrics Writer (preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '635dd51f-9968-44d3-b7fb-6d9a6bd613ae')]", + "AzureML Registry User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1823dd4f-9b8c-4ab6-ab4e-7397a3684615')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.machinelearningservices-workspace.{0}.{1}', replace('0.7.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "workspace": { + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2024-04-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('sku')]", + "tier": "[parameters('sku')]" + }, + "identity": "[variables('identity')]", + "properties": "[union(createObject('friendlyName', parameters('name'), 'storageAccount', parameters('associatedStorageAccountResourceId'), 'keyVault', parameters('associatedKeyVaultResourceId'), 'applicationInsights', parameters('associatedApplicationInsightsResourceId'), 'containerRegistry', parameters('associatedContainerRegistryResourceId'), 'hbiWorkspace', parameters('hbiWorkspace'), 'description', parameters('description'), 'discoveryUrl', parameters('discoveryUrl'), 'encryption', if(not(empty(parameters('customerManagedKey'))), createObject('status', 'Enabled', 'identity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), createObject('userAssignedIdentity', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/')))), null()), 'keyVaultProperties', createObject('keyVaultArmId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2], split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]), 'Microsoft.KeyVault/vaults', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))), 'keyIdentifier', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), reference('cMKKeyVault::cMKKey').keyUriWithVersion))), null()), 'imageBuildCompute', parameters('imageBuildCompute'), 'primaryUserAssignedIdentity', parameters('primaryUserAssignedIdentity'), 'systemDatastoresAuthMode', parameters('systemDatastoresAuthMode'), 'publicNetworkAccess', parameters('publicNetworkAccess'), 'serviceManagedResourcesSettings', parameters('serviceManagedResourcesSettings'), 'featureStoreSettings', parameters('featureStoreSettings'), 'hubResourceId', parameters('hubResourceId'), 'managedNetwork', parameters('managedNetworkSettings'), 'serverlessComputeSettings', parameters('serverlessComputeSettings'), 'workspaceHubConfig', parameters('workspaceHubConfig')), if(not(empty(parameters('sharedPrivateLinkResources'))), createObject('sharedPrivateLinkResources', parameters('sharedPrivateLinkResources')), createObject()))]", + "kind": "[parameters('kind')]", + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "workspace_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.MachineLearningServices/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "workspace_diagnosticSettings": { + "copy": { + "name": "workspace_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.MachineLearningServices/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "workspace_roleAssignments": { + "copy": { + "name": "workspace_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.MachineLearningServices/workspaces/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "workspace" + ] + }, + "workspace_computes": { + "copy": { + "name": "workspace_computes", + "count": "[length(coalesce(parameters('computes'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-compute', parameters('name'), coalesce(parameters('computes'), createArray())[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "machineLearningWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].name]" + }, + "location": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].location]" + }, + "sku": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'sku')]" + }, + "managedIdentities": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'managedIdentities')]" + }, + "tags": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'tags')]" + }, + "deployCompute": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'deployCompute')]" + }, + "computeLocation": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'computeLocation')]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'description')]" + }, + "disableLocalAuth": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'disableLocalAuth')]" + }, + "resourceId": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'resourceId')]" + }, + "computeType": { + "value": "[coalesce(parameters('computes'), createArray())[copyIndex()].computeType]" + }, + "properties": { + "value": "[tryGet(coalesce(parameters('computes'), createArray())[copyIndex()], 'properties')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "8580750401363518569" + }, + "name": "Machine Learning Services Workspaces Computes", + "description": "This module deploys a Machine Learning Services Workspaces Compute.\n\nAttaching a compute is not idempotent and will fail in case you try to redeploy over an existing compute in AML (see parameter `deployCompute`).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + } + }, + "parameters": { + "machineLearningWorkspaceName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Machine Learning Workspace. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "minLength": 2, + "maxLength": 16, + "metadata": { + "description": "Required. Name of the compute." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Specifies the location of the resource." + } + }, + "sku": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Basic", + "Free", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Specifies the sku, also referred as \"edition\". Required for creating a compute resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Contains resource tags defined as key-value pairs. Ignored when attaching a compute resource, i.e. when you provide a resource ID." + } + }, + "deployCompute": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Flag to specify whether to deploy the compute. Required only for attach (i.e. providing a resource ID), as in this case the operation is not idempotent, i.e. a second deployment will fail. Therefore, this flag needs to be set to \"false\" as long as the compute resource exists." + } + }, + "computeLocation": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for the underlying compute. Ignored when attaching a compute resource, i.e. when you provide a resource ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the Machine Learning compute." + } + }, + "disableLocalAuth": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Opt-out of local authentication and ensure customers can use only MSI and AAD exclusively for authentication." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. ARM resource ID of the underlying compute." + } + }, + "computeType": { + "type": "string", + "allowedValues": [ + "AKS", + "AmlCompute", + "ComputeInstance", + "Databricks", + "DataFactory", + "DataLakeAnalytics", + "HDInsight", + "Kubernetes", + "SynapseSpark", + "VirtualMachine" + ], + "metadata": { + "description": "Required. Set the object type." + } + }, + "properties": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The properties of the compute. Will be ignored in case \"resourceId\" is set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + } + }, + "variables": { + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]" + }, + "resources": { + "machineLearningWorkspace": { + "existing": true, + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('machineLearningWorkspaceName')]" + }, + "compute": { + "condition": "[equals(parameters('deployCompute'), true())]", + "type": "Microsoft.MachineLearningServices/workspaces/computes", + "apiVersion": "2022-10-01", + "name": "[format('{0}/{1}', parameters('machineLearningWorkspaceName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[if(empty(parameters('resourceId')), parameters('tags'), null())]", + "sku": "[if(empty(parameters('resourceId')), createObject('name', parameters('sku'), 'tier', parameters('sku')), null())]", + "identity": "[if(empty(parameters('resourceId')), variables('identity'), null())]", + "properties": "[union(createObject('description', parameters('description'), 'disableLocalAuth', parameters('disableLocalAuth'), 'computeType', parameters('computeType')), if(not(empty(parameters('resourceId'))), createObject('resourceId', parameters('resourceId')), createObject('computeLocation', parameters('computeLocation'), 'properties', parameters('properties'))))]", + "dependsOn": [ + "machineLearningWorkspace" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the compute." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the compute." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces/computes', parameters('machineLearningWorkspaceName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the compute was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('compute', '2022-10-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('compute', '2022-10-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "workspace", + "workspace_privateEndpoints" + ] + }, + "workspace_connections": { + "copy": { + "name": "workspace_connections", + "count": "[length(parameters('connections'))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-{1}-connection', parameters('name'), parameters('connections')[copyIndex()].name)]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "machineLearningWorkspaceName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[parameters('connections')[copyIndex()].name]" + }, + "category": { + "value": "[parameters('connections')[copyIndex()].category]" + }, + "expiryTime": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'expiryTime')]" + }, + "isSharedToAll": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'isSharedToAll')]" + }, + "metadata": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'metadata')]" + }, + "sharedUserList": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'sharedUserList')]" + }, + "target": { + "value": "[parameters('connections')[copyIndex()].target]" + }, + "value": { + "value": "[tryGet(parameters('connections')[copyIndex()], 'value')]" + }, + "connectionProperties": { + "value": "[parameters('connections')[copyIndex()].connectionProperties]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "2277907099827503661" + }, + "name": "Machine Learning Services Workspaces Connections", + "description": "This module creates a connection in a Machine Learning Services workspace.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "metadataType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. The metadata key-value pairs." + } + } + }, + "categoryType": { + "type": "string", + "allowedValues": [ + "ADLSGen2", + "AIServices", + "AmazonMws", + "AmazonRdsForOracle", + "AmazonRdsForSqlServer", + "AmazonRedshift", + "AmazonS3Compatible", + "ApiKey", + "AzureBlob", + "AzureDataExplorer", + "AzureDatabricksDeltaLake", + "AzureMariaDb", + "AzureMySqlDb", + "AzureOneLake", + "AzureOpenAI", + "AzurePostgresDb", + "AzureSqlDb", + "AzureSqlMi", + "AzureSynapseAnalytics", + "AzureTableStorage", + "BingLLMSearch", + "Cassandra", + "CognitiveSearch", + "CognitiveService", + "Concur", + "ContainerRegistry", + "CosmosDb", + "CosmosDbMongoDbApi", + "Couchbase", + "CustomKeys", + "Db2", + "Drill", + "Dynamics", + "DynamicsAx", + "DynamicsCrm", + "Eloqua", + "FileServer", + "FtpServer", + "GenericContainerRegistry", + "GenericHttp", + "GenericRest", + "Git", + "GoogleAdWords", + "GoogleBigQuery", + "GoogleCloudStorage", + "Greenplum", + "Hbase", + "Hdfs", + "Hive", + "Hubspot", + "Impala", + "Informix", + "Jira", + "Magento", + "MariaDb", + "Marketo", + "MicrosoftAccess", + "MongoDbAtlas", + "MongoDbV2", + "MySql", + "Netezza", + "ODataRest", + "Odbc", + "Office365", + "OpenAI", + "Oracle", + "OracleCloudStorage", + "OracleServiceCloud", + "PayPal", + "Phoenix", + "PostgreSql", + "Presto", + "PythonFeed", + "QuickBooks", + "Redis", + "Responsys", + "S3", + "Salesforce", + "SalesforceMarketingCloud", + "SalesforceServiceCloud", + "SapBw", + "SapCloudForCustomer", + "SapEcc", + "SapHana", + "SapOpenHub", + "SapTable", + "Serp", + "Serverless", + "ServiceNow", + "Sftp", + "SharePointOnlineList", + "Shopify", + "Snowflake", + "Spark", + "SqlServer", + "Square", + "Sybase", + "Teradata", + "Vertica", + "WebTable", + "Xero", + "Zoho" + ], + "metadata": { + "__bicep_export!": true + } + }, + "aadAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AAD" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + } + }, + "accessKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccessKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionAccessKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "accountKeyAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "AccountKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionAccountKey", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "apiKeyAuthWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ApiKey" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionApiKeyType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "customKeysWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "CustomKeys" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/customKeysType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "managedIdentityAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ManagedIdentity" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionManagedIdentityType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "noneAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "None" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + } + } + }, + "oauth2AuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "OAuth2" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionOAuth2Type", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "patAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "PAT" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionPersonalAccessTokenType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "sasAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "SAS" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionSharedAccessSignatureType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "servicePrincipalAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "ServicePrincipal" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionServicePrincipalType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "usernamePasswordAuthTypeWorkspaceConnectionPropertyType": { + "type": "object", + "properties": { + "authType": { + "type": "string", + "allowedValues": [ + "UsernamePassword" + ], + "metadata": { + "description": "Required. The authentication type of the connection target." + } + }, + "credentials": { + "$ref": "#/definitions/workspaceConnectionUsernamePasswordType", + "metadata": { + "description": "Required. The credentials for the connection." + } + } + } + }, + "customKeysType": { + "type": "object", + "properties": { + "keys": { + "type": "object", + "properties": {}, + "additionalProperties": { + "type": "string", + "metadata": { + "description": "Required. Key-value pairs for the custom keys." + } + }, + "metadata": { + "description": "Required. The custom keys for the connection." + } + } + } + }, + "workspaceConnectionAccessKeyType": { + "type": "object", + "properties": { + "accessKeyId": { + "type": "string", + "metadata": { + "description": "Required. The connection access key ID." + } + }, + "secretAccessKey": { + "type": "string", + "metadata": { + "description": "Required. The connection secret access key." + } + } + } + }, + "workspaceConnectionAccountKey": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection key." + } + } + } + }, + "workspaceConnectionApiKeyType": { + "type": "object", + "properties": { + "key": { + "type": "string", + "metadata": { + "description": "Required. The connection API key." + } + } + } + }, + "workspaceConnectionManagedIdentityType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity ID." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The connection managed identity resource ID." + } + } + } + }, + "workspaceConnectionOAuth2Type": { + "type": "object", + "properties": { + "authUrl": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection auth URL. Required by Concur connection category." + } + }, + "clientId": { + "type": "string", + "minLength": 36, + "maxLength": 36, + "metadata": { + "description": "Required. The connection client ID in the format of UUID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "developerToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection developer token. Required by GoogleAdWords connection category." + } + }, + "password": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection password. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + }, + "refreshToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection refresh token. Required by GoogleBigQuery, GoogleAdWords, Hubspot, QuickBooks, Square, Xero and Zoho connection categories." + } + }, + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The connection tenant ID. Required by QuickBooks and Xero connection categories." + } + }, + "username": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection username. Required by Concur and ServiceNow connection categories where AccessToken grant type is 'Password'." + } + } + } + }, + "workspaceConnectionPersonalAccessTokenType": { + "type": "object", + "properties": { + "pat": { + "type": "string", + "metadata": { + "description": "Required. The connection personal access token." + } + } + } + }, + "workspaceConnectionSharedAccessSignatureType": { + "type": "object", + "properties": { + "sas": { + "type": "string", + "metadata": { + "description": "Required. The connection SAS token." + } + } + } + }, + "workspaceConnectionServicePrincipalType": { + "type": "object", + "properties": { + "clientId": { + "type": "string", + "metadata": { + "description": "Required. The connection client ID." + } + }, + "clientSecret": { + "type": "string", + "metadata": { + "description": "Required. The connection client secret." + } + }, + "tenantId": { + "type": "string", + "metadata": { + "description": "Required. The connection tenant ID." + } + } + } + }, + "workspaceConnectionUsernamePasswordType": { + "type": "object", + "properties": { + "password": { + "type": "string", + "metadata": { + "description": "Required. The connection password." + } + }, + "securityToken": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The connection security token. Required by connections like SalesForce for extra security in addition to 'UsernamePassword'." + } + }, + "username": { + "type": "string", + "metadata": { + "description": "Required. The connection username." + } + } + } + }, + "connectionPropertyType": { + "type": "secureObject", + "discriminator": { + "propertyName": "authType", + "mapping": { + "AAD": { + "$ref": "#/definitions/aadAuthTypeWorkspaceConnectionPropertyType" + }, + "AccessKey": { + "$ref": "#/definitions/accessKeyAuthTypeWorkspaceConnectionPropertyType" + }, + "ApiKey": { + "$ref": "#/definitions/apiKeyAuthWorkspaceConnectionPropertyType" + }, + "CustomKeys": { + "$ref": "#/definitions/customKeysWorkspaceConnectionPropertyType" + }, + "ManagedIdentity": { + "$ref": "#/definitions/managedIdentityAuthTypeWorkspaceConnectionPropertyType" + }, + "None": { + "$ref": "#/definitions/noneAuthTypeWorkspaceConnectionPropertyType" + }, + "OAuth2": { + "$ref": "#/definitions/oauth2AuthTypeWorkspaceConnectionPropertyType" + }, + "PAT": { + "$ref": "#/definitions/patAuthTypeWorkspaceConnectionPropertyType" + }, + "SAS": { + "$ref": "#/definitions/sasAuthTypeWorkspaceConnectionPropertyType" + }, + "ServicePrincipal": { + "$ref": "#/definitions/servicePrincipalAuthTypeWorkspaceConnectionPropertyType" + }, + "UsernamePassword": { + "$ref": "#/definitions/usernamePasswordAuthTypeWorkspaceConnectionPropertyType" + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the connection to create." + } + }, + "machineLearningWorkspaceName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent Machine Learning Workspace. Required if the template is used in a standalone deployment." + } + }, + "category": { + "$ref": "#/definitions/categoryType", + "metadata": { + "description": "Required. Category of the connection." + } + }, + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiry time of the connection." + } + }, + "isSharedToAll": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Indicates whether the connection is shared to all users in the workspace." + } + }, + "metadata": { + "$ref": "#/definitions/metadataType", + "defaultValue": {}, + "metadata": { + "description": "Optional. User metadata for the connection." + } + }, + "sharedUserList": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The shared user list of the connection." + } + }, + "target": { + "type": "string", + "metadata": { + "description": "Required. The target of the connection." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Value details of the workspace connection." + } + }, + "connectionProperties": { + "$ref": "#/definitions/connectionPropertyType", + "metadata": { + "description": "Required. The properties of the connection, specific to the auth type." + } + } + }, + "resources": { + "machineLearningWorkspace": { + "existing": true, + "type": "Microsoft.MachineLearningServices/workspaces", + "apiVersion": "2022-10-01", + "name": "[parameters('machineLearningWorkspaceName')]" + }, + "connection": { + "type": "Microsoft.MachineLearningServices/workspaces/connections", + "apiVersion": "2024-04-01", + "name": "[format('{0}/{1}', parameters('machineLearningWorkspaceName'), parameters('name'))]", + "properties": "[union(createObject('category', parameters('category'), 'expiryTime', parameters('expiryTime'), 'isSharedToAll', parameters('isSharedToAll'), 'metadata', parameters('metadata'), 'sharedUserList', parameters('sharedUserList'), 'target', parameters('target'), 'value', parameters('value')), parameters('connectionProperties'))]", + "dependsOn": [ + "machineLearningWorkspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the connection." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces/connections', parameters('machineLearningWorkspaceName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the connection." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the connection was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "workspace" + ] + }, + "workspace_privateEndpoints": { + "copy": { + "name": "workspace_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-workspace-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'amlworkspace')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "3308873178893851812" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + } + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.7.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" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5805178546717255803" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfig": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(and(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds', 0), ''), if(and(not(empty(reference('privateEndpoint').privateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds', 0), ''), ''))]" + } + } + } + }, + "dependsOn": [ + "workspace" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the machine learning service." + }, + "value": "[resourceId('Microsoft.MachineLearningServices/workspaces', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the machine learning service was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the machine learning service." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('workspace', '2024-04-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('workspace', '2024-04-01-preview', 'full').location]" + } + } + } + } + }, + "keyVaultAccess": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyvault', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('keyVaultName')]" + }, + "accessPolicies": { + "value": [ + { + "objectId": "[reference('project').outputs.systemAssignedMIPrincipalId.value]", + "permissions": { + "secrets": [ + "get", + "list" + ] + } + } + ] + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "10085839006881327962" + }, + "name": "Key Vaults", + "description": "This module deploys a Key Vault.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroup": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + } + }, + "nullable": true + }, + "secretsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the secret is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the secret will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the secret becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the secret." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + } + }, + "nullable": true + }, + "keysType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the key is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the key will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the key becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the key." + } + }, + "curveName": { + "type": "string", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "nullable": true, + "metadata": { + "description": "Optional. The elliptic curve name. Only works if \"keySize\" equals \"EC\" or \"EC-HSM\". Default is \"P-256\"." + } + }, + "keyOps": { + "type": "array", + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "release", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. The allowed operations on this key." + } + }, + "keySize": { + "type": "int", + "allowedValues": [ + 2048, + 3072, + 4096 + ], + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. Only works if \"keySize\" equals \"RSA\" or \"RSA-HSM\". Default is \"4096\"." + } + }, + "kty": { + "type": "string", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the key. Default is \"EC\"." + } + }, + "releasePolicy": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Content type and version of key release policy." + } + }, + "data": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Blob encoding the policy rules under which the key can be released." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "rotationPolicy": { + "$ref": "#/definitions/rotationPoliciesType", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + } + }, + "nullable": true + }, + "rotationPoliciesType": { + "type": "object", + "properties": { + "attributes": { + "type": "object", + "properties": { + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiration time for the new key version. It should be in ISO8601 format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The attributes of key rotation policy." + } + }, + "lifetimeActions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Notify", + "Rotate" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of action." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The action of key rotation policy lifetimeAction." + } + }, + "trigger": { + "type": "object", + "properties": { + "timeAfterCreate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration after key creation to rotate the key. It only applies to rotate. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + }, + "timeBeforeExpiry": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration before key expiring to rotate or notify. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The trigger of key rotation policy lifetimeAction." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The lifetimeActions for key rotation action." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Key Vault. Must be globally unique." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. All access policies to create." + } + }, + "secrets": { + "$ref": "#/definitions/secretsType", + "nullable": true, + "metadata": { + "description": "Optional. All secrets to create." + } + }, + "keys": { + "$ref": "#/definitions/keysType", + "nullable": true, + "metadata": { + "description": "Optional. All keys to create." + } + }, + "enableVaultForDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for deployment by script or compute." + } + }, + "enableVaultForTemplateDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for a template deployment." + } + }, + "enableVaultForDiskEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios." + } + }, + "enableSoftDelete": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Switch to enable/disable Key Vault's soft delete feature." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 90, + "metadata": { + "description": "Optional. softDelete data retention days. It accepts >=7 and <=90." + } + }, + "enableRbacAuthorization": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC." + } + }, + "createMode": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." + } + }, + "sku": { + "type": "string", + "defaultValue": "premium", + "allowedValues": [ + "premium", + "standard" + ], + "metadata": { + "description": "Optional. Specifies the SKU for the vault." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Rules governing the accessibility of the resource from specific network locations." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Certificates Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a4417e6f-fecd-4de8-b567-7b0420556985')]", + "Key Vault Certificate User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('0.9.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" + } + } + } + } + }, + "keyVault": { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "enabledForDeployment": "[parameters('enableVaultForDeployment')]", + "enabledForTemplateDeployment": "[parameters('enableVaultForTemplateDeployment')]", + "enabledForDiskEncryption": "[parameters('enableVaultForDiskEncryption')]", + "enableSoftDelete": "[parameters('enableSoftDelete')]", + "softDeleteRetentionInDays": "[parameters('softDeleteRetentionInDays')]", + "enableRbacAuthorization": "[parameters('enableRbacAuthorization')]", + "createMode": "[parameters('createMode')]", + "enablePurgeProtection": "[if(parameters('enablePurgeProtection'), parameters('enablePurgeProtection'), null())]", + "tenantId": "[subscription().tenantId]", + "accessPolicies": "[variables('formattedAccessPolicies')]", + "sku": { + "name": "[parameters('sku')]", + "family": "A" + }, + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(coalesce(parameters('privateEndpoints'), createArray()))), empty(coalesce(parameters('networkAcls'), createObject()))), 'Disabled', null()))]" + } + }, + "keyVault_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_diagnosticSettings": { + "copy": { + "name": "keyVault_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_roleAssignments": { + "copy": { + "name": "keyVault_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_accessPolicies": { + "condition": "[not(empty(parameters('accessPolicies')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-AccessPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('name')]" + }, + "accessPolicies": { + "value": "[parameters('accessPolicies')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "7494731697751039419" + }, + "name": "Key Vault Access Policies", + "description": "This module deploys a Key Vault Access Policy.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ] + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "policies": { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", + "properties": { + "accessPolicies": "[variables('formattedAccessPolicies')]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the access policies assignment was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policies assignment." + }, + "value": "add" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policies assignment." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_secrets": { + "copy": { + "name": "keyVault_secrets", + "count": "[length(coalesce(parameters('secrets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Secret-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].value]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'enabled')]" + }, + "attributesExp": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'exp')]" + }, + "attributesNbf": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'nbf')]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "114626909766354577" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "contentType": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secret": { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "contentType": "[parameters('contentType')]", + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "value": "[parameters('value')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "secret_roleAssignments": { + "copy": { + "name": "secret_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "secret" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secret." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secret." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the secret was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_keys": { + "copy": { + "name": "keyVault_keys", + "count": "[length(coalesce(parameters('keys'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Key-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('keys'), createArray())[copyIndex()].name]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'enabled')]" + }, + "attributesExp": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'exp')]" + }, + "attributesNbf": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'nbf')]" + }, + "curveName": "[if(and(not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA')), not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM'))), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'curveName'), 'P-256')), createObject('value', null()))]", + "keyOps": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keyOps')]" + }, + "keySize": "[if(or(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA'), equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM')), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keySize'), 4096)), createObject('value', null()))]", + "releasePolicy": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'releasePolicy'), createObject())]" + }, + "kty": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'EC')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "rotationPolicy": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'rotationPolicy')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "14269695922191217406" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "curveName": { + "type": "string", + "defaultValue": "P-256", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "metadata": { + "description": "Optional. The elliptic curve name." + } + }, + "keyOps": { + "type": "array", + "nullable": true, + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "metadata": { + "description": "Optional. Array of JsonWebKeyOperation." + } + }, + "keySize": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." + } + }, + "kty": { + "type": "string", + "defaultValue": "EC", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "metadata": { + "description": "Optional. The type of the key." + } + }, + "releasePolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "rotationPolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy properties object." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "key": { + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "curveName": "[parameters('curveName')]", + "keyOps": "[parameters('keyOps')]", + "keySize": "[parameters('keySize')]", + "kty": "[parameters('kty')]", + "rotationPolicy": "[coalesce(parameters('rotationPolicy'), createObject())]", + "release_policy": "[coalesce(parameters('releasePolicy'), createObject())]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "key_roleAssignments": { + "copy": { + "name": "key_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "key" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_privateEndpoints": { + "copy": { + "name": "keyVault_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyVault-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "1277254088602407590" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + } + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to. If used with private link service connection, this property must be defined as empty string array `[]`." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone group to configure for the private endpoint." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "5805178546717255803" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDnsZoneConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", + "input": { + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" + } + } + } + ] + }, + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-11-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-11-01', 'full').location]" + }, + "customDnsConfig": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceIds": { + "type": "array", + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + }, + "value": "[reference('privateEndpoint').networkInterfaces]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(and(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties, 'groupIds', 0), ''), if(and(not(empty(reference('privateEndpoint').privateLinkServiceConnections)), greater(length(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds')), 0)), coalesce(tryGet(reference('privateEndpoint').privateLinkServiceConnections[0].properties, 'groupIds', 0), ''), ''))]" + } + } + } + }, + "dependsOn": [ + "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]" + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the key vault." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('keyVault_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } + } + } + } + }, + "dependsOn": [ + "keyVault", + "project" + ] + }, + "mlServiceRoleAssigned": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-roleassignment', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('userAssignedName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "roleAssignments": { + "copy": [ + { + "name": "value", + "count": "[length(parameters('roleDefinitionIdOrName'))]", + "input": "[createObject('principalId', reference('project').outputs.systemAssignedMIPrincipalId.value, 'roleDefinitionIdOrName', parameters('roleDefinitionIdOrName')[copyIndex('value')], 'principalType', 'ServicePrincipal')]" + } + ] + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "10609859695208799167" + }, + "name": "User Assigned Identities", + "description": "This module deploys a User Assigned Identity.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "federatedIdentityCredentialsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the federated identity credential." + } + }, + "audiences": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external identity." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the User Assigned Identity." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "federatedIdentityCredentials": { + "$ref": "#/definitions/federatedIdentityCredentialsType", + "metadata": { + "description": "Optional. The federated identity credentials list to indicate which token from the external IdP should be trusted by your application. Federated identity credentials are supported on applications only. A maximum of 20 federated identity credentials can be added per application object." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Managed Identity Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e40ec5ca-96e0-45a2-b4ff-59039f2c2b59')]", + "Managed Identity Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f1a07417-d97a-45cb-824c-7a7467783830')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.managedidentity-userassignedidentity.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "userAssignedIdentity": { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]" + }, + "userAssignedIdentity_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_roleAssignments": { + "copy": { + "name": "userAssignedIdentity_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ManagedIdentity/userAssignedIdentities/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "userAssignedIdentity" + ] + }, + "userAssignedIdentity_federatedIdentityCredentials": { + "copy": { + "name": "userAssignedIdentity_federatedIdentityCredentials", + "count": "[length(coalesce(parameters('federatedIdentityCredentials'), createArray()))]", + "mode": "serial", + "batchSize": 1 + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-UserMSI-FederatedIdentityCredential-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].name]" + }, + "userAssignedIdentityName": { + "value": "[parameters('name')]" + }, + "audiences": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].audiences]" + }, + "issuer": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].issuer]" + }, + "subject": { + "value": "[coalesce(parameters('federatedIdentityCredentials'), createArray())[copyIndex()].subject]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "3716898257490923786" + }, + "name": "User Assigned Identity Federated Identity Credential", + "description": "This module deploys a User Assigned Identity Federated Identity Credential.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "userAssignedIdentityName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent user assigned identity. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "audiences": { + "type": "array", + "metadata": { + "description": "Required. The list of audiences that can appear in the issued token. Should be set to api://AzureADTokenExchange for Azure AD. It says what Microsoft identity platform should accept in the aud claim in the incoming token. This value represents Azure AD in your external identity provider and has no fixed value across identity providers - you might need to create a new application registration in your IdP to serve as the audience of this token." + } + }, + "issuer": { + "type": "string", + "metadata": { + "description": "Required. The URL of the issuer to be trusted. Must match the issuer claim of the external token being exchanged." + } + }, + "subject": { + "type": "string", + "metadata": { + "description": "Required. The identifier of the external software workload within the external identity provider. Like the audience value, it has no fixed format, as each IdP uses their own - sometimes a GUID, sometimes a colon delimited identifier, sometimes arbitrary strings. The value here must match the sub claim within the token presented to Azure AD." + } + } + }, + "resources": [ + { + "type": "Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials", + "apiVersion": "2023-01-31", + "name": "[format('{0}/{1}', parameters('userAssignedIdentityName'), parameters('name'))]", + "properties": { + "audiences": "[parameters('audiences')]", + "issuer": "[parameters('issuer')]", + "subject": "[parameters('subject')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the federated identity credential." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the federated identity credential." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/federatedIdentityCredentials', parameters('userAssignedIdentityName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the federated identity credential was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "userAssignedIdentity" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the user assigned identity." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the user assigned identity." + }, + "value": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('name'))]" + }, + "principalId": { + "type": "string", + "metadata": { + "description": "The principal ID (object ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').principalId]" + }, + "clientId": { + "type": "string", + "metadata": { + "description": "The client ID (application ID) of the user assigned identity." + }, + "value": "[reference('userAssignedIdentity').clientId]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the user assigned identity was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('userAssignedIdentity', '2023-01-31', 'full').location]" + } + } + } + }, + "dependsOn": [ + "project" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the machine learning workspace were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "projectResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the machine learning workspace." + }, + "value": "[reference('project').outputs.resourceId.value]" + }, + "projectName": { + "type": "string", + "metadata": { + "description": "The resource name of the machine learning workspace." + }, + "value": "[reference('project').outputs.name.value]" + }, + "projectPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the machine learning workspace." + }, + "value": "[reference('project').outputs.systemAssignedMIPrincipalId.value]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/ml-project/tests/e2e/defaults/dependencies.bicep b/avm/ptn/azd/ml-project/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..8936dfcb78 --- /dev/null +++ b/avm/ptn/azd/ml-project/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,60 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the AI Studio Hub Resource to create.') +param hubName string + +@description('Required. The name of the key vault to create.') +param keyVaultName string + +@description('Required. The name of the storage account to create.') +param storageAccountName string + +@description('Optional. Tags of the resource.') +@metadata({ + example: ''' + { + "key1": "value1" + "key2": "value2" + } + ''' +}) +param tags object? + +module storageAccount 'br/public:avm/res/storage/storage-account:0.9.1' = { + name: '${uniqueString(deployment().name, location)}-storage' + params: { + name: storageAccountName + tags: tags + location: location + } +} + +module keyvault 'br/public:avm/res/key-vault/vault:0.9.0' = { + name: '${uniqueString(deployment().name, location)}-keyvault' + params: { + enablePurgeProtection: false + location: location + name: keyVaultName + } +} + +module hub 'br/public:avm/res/machine-learning-services/workspace:0.7.0' = { + name: '${uniqueString(deployment().name, location)}-hub' + params: { + name: hubName + tags: tags + location: location + sku: 'Basic' + kind: 'Hub' + associatedKeyVaultResourceId: keyvault.outputs.resourceId + associatedStorageAccountResourceId: storageAccount.outputs.resourceId + } +} + +@description('The resource ID of the AI Studio Hub Resource.') +output hubResourceId string = hub.outputs.resourceId + +@description('The name of the key vault.') +output keyVaultName string = keyvault.outputs.name + diff --git a/avm/ptn/azd/ml-project/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/ml-project/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..996d63a5bd --- /dev/null +++ b/avm/ptn/azd/ml-project/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,61 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-azd-ml-project-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'mlpmin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module dependencies 'dependencies.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-dependencies' + scope: resourceGroup + params: { + hubName: '${namePrefix}${serviceShort}hub001' + keyVaultName: '${namePrefix}${serviceShort}kv001' + storageAccountName: '${namePrefix}${serviceShort}sa001' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + keyVaultName: dependencies.outputs.keyVaultName + userAssignedName: '${namePrefix}${serviceShort}uai001' + hubResourceId: dependencies.outputs.hubResourceId + } + } +] diff --git a/avm/ptn/azd/ml-project/version.json b/avm/ptn/azd/ml-project/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/ml-project/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From a49727224d91a95597b7108cf0a4a589af6f023a Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Fri, 11 Oct 2024 09:46:57 +0200 Subject: [PATCH 09/17] fix: cognitive services readme update (#3508) ## Description Fix readme regen Add small change to trigger publishing ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cognitive-services.account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=users%2Feriqua%2Fcognitive-readme)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/cognitive-services/account/README.md | 8 ++++---- avm/res/cognitive-services/account/main.bicep | 2 +- avm/res/cognitive-services/account/main.json | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index fb852b55a3..9462bf4a9b 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -1614,7 +1614,7 @@ param tags = { | Parameter | Type | Description | | :-- | :-- | :-- | -| [`kind`](#parameter-kind) | string | Kind of the Cognitive Services. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. | +| [`kind`](#parameter-kind) | string | Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. | | [`name`](#parameter-name) | string | The name of Cognitive Services account. | **Conditional parameters** @@ -1638,7 +1638,7 @@ param tags = { | [`location`](#parameter-location) | string | Location for all Resources. | | [`lock`](#parameter-lock) | object | The lock settings of the service. | | [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. | -| [`migrationToken`](#parameter-migrationtoken) | string | Resource migration token. | +| [`migrationToken`](#parameter-migrationtoken) | securestring | Resource migration token. | | [`networkAcls`](#parameter-networkacls) | object | A collection of rules governing the accessibility from specific network locations. | | [`privateEndpoints`](#parameter-privateendpoints) | array | Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. | | [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set. | @@ -1652,7 +1652,7 @@ param tags = { ### Parameter: `kind` -Kind of the Cognitive Services. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. +Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. - Required: Yes - Type: string @@ -2114,7 +2114,7 @@ The resource ID(s) to assign to the resource. Required if a user assigned identi Resource migration token. - Required: No -- Type: string +- Type: securestring ### Parameter: `networkAcls` diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index d7c788c144..96147cc72d 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -5,7 +5,7 @@ metadata owner = 'Azure/module-maintainers' @description('Required. The name of Cognitive Services account.') param name string -@description('Required. Kind of the Cognitive Services. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@description('Required. Kind of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') @allowed([ 'AIServices' 'AnomalyDetector' diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 7f45a5e8dc..013a5b598c 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "325704537018634474" + "templateHash": "9722036366573656954" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -668,7 +668,7 @@ "TextTranslation" ], "metadata": { - "description": "Required. Kind of the Cognitive Services. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Required. Kind of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." } }, "sku": { From a14856cbfc1e22c4a2bd5acde7f354189203b103 Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Fri, 11 Oct 2024 10:48:51 +0200 Subject: [PATCH 10/17] fix: Trigger azd ml project publishing (#3511) ## Description fix issue template order add small change to trigger publishing ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.ml-project](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml/badge.svg?branch=users%2Feriqua%2Fissue-temp)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- .github/ISSUE_TEMPLATE/avm_module_issue.yml | 2 +- avm/ptn/azd/ml-project/README.md | 4 ++-- avm/ptn/azd/ml-project/main.bicep | 5 ++--- avm/ptn/azd/ml-project/main.json | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 719a8c2982..1c5486a04e 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -51,8 +51,8 @@ body: - "avm/ptn/azd/apim-api" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" - - "avm/ptn/azd/ml-project" - "avm/ptn/azd/ml-hub-dependencies" + - "avm/ptn/azd/ml-project" - "avm/ptn/azd/monitoring" - "avm/ptn/deployment-script/import-image-to-acr" - "avm/ptn/dev-ops/cicd-agents-and-runners" diff --git a/avm/ptn/azd/ml-project/README.md b/avm/ptn/azd/ml-project/README.md index dc07753fe1..adc6341c6e 100644 --- a/avm/ptn/azd/ml-project/README.md +++ b/avm/ptn/azd/ml-project/README.md @@ -142,7 +142,7 @@ param location = '' | [`projectKind`](#parameter-projectkind) | string | The type of Azure Machine Learning workspace to create. | | [`projectManagedIdentities`](#parameter-projectmanagedidentities) | object | The managed identity definition for the machine learning resource. At least one identity type is required. | | [`projectSku`](#parameter-projectsku) | string | Specifies the SKU, also referred as 'edition' of the Azure Machine Learning workspace. | -| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this machine learning workspace. For security reasons it should be disabled. | | [`roleDefinitionIdOrName`](#parameter-roledefinitionidorname) | array | 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'. Default roles: AzureML Data Scientist, Azure Machine Learning Workspace Connection Secrets Reader. | | [`tags`](#parameter-tags) | object | Tags of the resource. | @@ -268,7 +268,7 @@ Specifies the SKU, also referred as 'edition' of the Azure Machine Learning work ### Parameter: `publicNetworkAccess` -Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled. +Whether or not public network access is allowed for this machine learning workspace. For security reasons it should be disabled. - Required: No - Type: string diff --git a/avm/ptn/azd/ml-project/main.bicep b/avm/ptn/azd/ml-project/main.bicep index effc6771d5..96179ddb4b 100644 --- a/avm/ptn/azd/ml-project/main.bicep +++ b/avm/ptn/azd/ml-project/main.bicep @@ -45,7 +45,7 @@ param projectKind string = 'Project' @description('Optional. The flag to signal HBI data in the workspace and reduce diagnostic data collected by the service.') param hbiWorkspace bool = false -@description('Optional. Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled.') +@description('Optional. Whether or not public network access is allowed for this machine learning workspace. For security reasons it should be disabled.') @allowed([ 'Enabled' 'Disabled' @@ -121,7 +121,7 @@ module keyVaultAccess 'br/public:avm/res/key-vault/vault:0.9.0' = { accessPolicies: [ { objectId: project.outputs.systemAssignedMIPrincipalId - permissions: { secrets: [ 'get', 'list' ] } + permissions: { secrets: ['get', 'list'] } } ] enableTelemetry: enableTelemetry @@ -171,4 +171,3 @@ type managedIdentitiesType = { @description('Optional. The resource ID(s) to assign to the resource.') userAssignedResourceIds: string[]? } - diff --git a/avm/ptn/azd/ml-project/main.json b/avm/ptn/azd/ml-project/main.json index 01d5610330..f130a38a14 100644 --- a/avm/ptn/azd/ml-project/main.json +++ b/avm/ptn/azd/ml-project/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "12979908494001456774" + "templateHash": "15406074241490987266" }, "name": "Azd Machine Learning workspace", "description": "Create a machine learning workspace, configure the key vault access policy and assign role permissions to the machine learning instance.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", @@ -106,7 +106,7 @@ "Disabled" ], "metadata": { - "description": "Optional. Whether or not public network access is allowed for this machine learning resource. For security reasons it should be disabled." + "description": "Optional. Whether or not public network access is allowed for this machine learning workspace. For security reasons it should be disabled." } }, "hubResourceId": { From 1de95a621a74c12f51225bec1f7cae0bb32f138c Mon Sep 17 00:00:00 2001 From: "Jinlong Shi (MSFT)" <139106314+jerryshia@users.noreply.github.com> Date: Fri, 11 Oct 2024 16:50:47 +0800 Subject: [PATCH 11/17] feat: Add new ptn modules `avm/ptn/azd/aks`. (#3250) ## Description Fixes https://github.com/Azure/Azure-Verified-Modules/issues/1224. ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.aks](https://github.com/jerryshia/bicep-registry-modules/actions/workflows/avm.ptn.azd.aks.yml/badge.svg?branch=azd%2Faks)](https://github.com/jerryshia/bicep-registry-modules/actions/workflows/avm.ptn.azd.aks.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> Co-authored-by: Alexander Sehr --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .github/workflows/avm.ptn.azd.aks.yml | 88 + avm/ptn/azd/aks/README.md | 1045 ++ avm/ptn/azd/aks/main.bicep | 466 + avm/ptn/azd/aks/main.json | 9163 +++++++++++++++++ .../aks/tests/e2e/defaults/dependencies.bicep | 56 + .../aks/tests/e2e/defaults/main.test.bicep | 63 + .../azd/aks/tests/e2e/max/dependencies.bicep | 56 + avm/ptn/azd/aks/tests/e2e/max/main.test.bicep | 87 + avm/ptn/azd/aks/version.json | 7 + 11 files changed, 11033 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.aks.yml create mode 100644 avm/ptn/azd/aks/README.md create mode 100644 avm/ptn/azd/aks/main.bicep create mode 100644 avm/ptn/azd/aks/main.json create mode 100644 avm/ptn/azd/aks/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/aks/tests/e2e/max/dependencies.bicep create mode 100644 avm/ptn/azd/aks/tests/e2e/max/main.test.bicep create mode 100644 avm/ptn/azd/aks/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 73abc09b92..f5002e3373 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -13,6 +13,7 @@ #/avm/ptn/avd-lza/networking/ @Azure/avm-ptn-avd-lza-networking-module-owners-bicep @Azure/avm-module-reviewers-bicep #/avm/ptn/avd-lza/session-hosts/ @Azure/avm-ptn-avd-lza-sessionhosts-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/acr-container-app/ @Azure/avm-ptn-azd-acrcontainerapp-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/aks/ @Azure/avm-ptn-azd-aks-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 1c5486a04e..2d27f5792e 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -48,6 +48,7 @@ body: # - "avm/ptn/avd-lza/networking" # - "avm/ptn/avd-lza/session-hosts" - "avm/ptn/azd/acr-container-app" + - "avm/ptn/azd/aks" - "avm/ptn/azd/apim-api" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" diff --git a/.github/workflows/avm.ptn.azd.aks.yml b/.github/workflows/avm.ptn.azd.aks.yml new file mode 100644 index 0000000000..8197fd7c84 --- /dev/null +++ b/.github/workflows/avm.ptn.azd.aks.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.aks" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.aks.yml" + - "avm/ptn/azd/aks/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/aks" + workflowPath: ".github/workflows/avm.ptn.azd.aks.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/ptn/azd/aks/README.md b/avm/ptn/azd/aks/README.md new file mode 100644 index 0000000000..18098d7a71 --- /dev/null +++ b/avm/ptn/azd/aks/README.md @@ -0,0 +1,1045 @@ +# Azd AKS `[Azd/Aks]` + +Creates an Azure Kubernetes Service (AKS) cluster with a system agent pool as well as an additional user agent pool. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.ContainerRegistry/registries` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries) | +| `Microsoft.ContainerRegistry/registries/cacheRules` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/cacheRules) | +| `Microsoft.ContainerRegistry/registries/credentialSets` | [2023-11-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/credentialSets) | +| `Microsoft.ContainerRegistry/registries/replications` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/replications) | +| `Microsoft.ContainerRegistry/registries/scopeMaps` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/scopeMaps) | +| `Microsoft.ContainerRegistry/registries/webhooks` | [2023-06-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerRegistry/registries/webhooks) | +| `Microsoft.ContainerService/managedClusters` | [2024-03-02-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerService/2024-03-02-preview/managedClusters) | +| `Microsoft.ContainerService/managedClusters/agentPools` | [2023-07-02-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerService/2023-07-02-preview/managedClusters/agentPools) | +| `Microsoft.ContainerService/managedClusters/maintenanceConfigurations` | [2023-10-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.ContainerService/2023-10-01/managedClusters/maintenanceConfigurations) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.KeyVault/vaults` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults) | +| `Microsoft.KeyVault/vaults/accessPolicies` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/accessPolicies) | +| `Microsoft.KeyVault/vaults/keys` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/keys) | +| `Microsoft.KeyVault/vaults/secrets` | [2022-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2022-07-01/vaults/secrets) | +| `Microsoft.KubernetesConfiguration/extensions` | [2022-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KubernetesConfiguration/2022-03-01/extensions) | +| `Microsoft.KubernetesConfiguration/fluxConfigurations` | [2022-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KubernetesConfiguration/2022-03-01/fluxConfigurations) | +| `Microsoft.Network/privateEndpoints` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-04-01/privateEndpoints/privateDnsZoneGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/azd/aks:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module aks 'br/public:avm/ptn/azd/aks:' = { + name: 'aksDeployment' + params: { + // Required parameters + containerRegistryName: '' + keyVaultName: '' + logAnalyticsName: '' + name: '' + principalId: '' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "containerRegistryName": { + "value": "" + }, + "keyVaultName": { + "value": "" + }, + "logAnalyticsName": { + "value": "" + }, + "name": { + "value": "" + }, + "principalId": { + "value": "" + }, + // Non-required parameters + "location": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/aks:' + +// Required parameters +param containerRegistryName = '' +param keyVaultName = '' +param logAnalyticsName = '' +param name = '' +param principalId = '' +// Non-required parameters +param location = '' +``` + +
+

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

+ +via Bicep module + +```bicep +module aks 'br/public:avm/ptn/azd/aks:' = { + name: 'aksDeployment' + params: { + // Required parameters + containerRegistryName: '' + keyVaultName: '' + logAnalyticsName: '' + name: '' + principalId: '' + // Non-required parameters + acrSku: 'Basic' + agentPools: [ + { + maxPods: 30 + maxSurge: '33%' + mode: 'User' + name: 'npuserpool' + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'standard_a2' + } + ] + aksClusterRoleAssignmentName: '' + containerRegistryRoleName: '' + dnsPrefix: 'dep-dns-paamax' + location: '' + principalType: 'ServicePrincipal' + skuTier: 'Free' + webApplicationRoutingEnabled: true + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "containerRegistryName": { + "value": "" + }, + "keyVaultName": { + "value": "" + }, + "logAnalyticsName": { + "value": "" + }, + "name": { + "value": "" + }, + "principalId": { + "value": "" + }, + // Non-required parameters + "acrSku": { + "value": "Basic" + }, + "agentPools": { + "value": [ + { + "maxPods": 30, + "maxSurge": "33%", + "mode": "User", + "name": "npuserpool", + "osType": "Linux", + "type": "VirtualMachineScaleSets", + "vmSize": "standard_a2" + } + ] + }, + "aksClusterRoleAssignmentName": { + "value": "" + }, + "containerRegistryRoleName": { + "value": "" + }, + "dnsPrefix": { + "value": "dep-dns-paamax" + }, + "location": { + "value": "" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "skuTier": { + "value": "Free" + }, + "webApplicationRoutingEnabled": { + "value": true + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/aks:' + +// Required parameters +param containerRegistryName = '' +param keyVaultName = '' +param logAnalyticsName = '' +param name = '' +param principalId = '' +// Non-required parameters +param acrSku = 'Basic' +param agentPools = [ + { + maxPods: 30 + maxSurge: '33%' + mode: 'User' + name: 'npuserpool' + osType: 'Linux' + type: 'VirtualMachineScaleSets' + vmSize: 'standard_a2' + } +] +param aksClusterRoleAssignmentName = '' +param containerRegistryRoleName = '' +param dnsPrefix = 'dep-dns-paamax' +param location = '' +param principalType = 'ServicePrincipal' +param skuTier = 'Free' +param webApplicationRoutingEnabled = true +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containerRegistryName`](#parameter-containerregistryname) | string | Name of your Azure Container Registry. | +| [`keyVaultName`](#parameter-keyvaultname) | string | Name of the Key Vault. Must be globally unique. | +| [`logAnalyticsName`](#parameter-loganalyticsname) | string | The name of the connected log analytics workspace. | +| [`name`](#parameter-name) | string | The name of the parent managed cluster. Required if the template is used in a standalone deployment. | +| [`principalId`](#parameter-principalid) | string | Id of the user or app to assign application roles. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`appGatewayResourceId`](#parameter-appgatewayresourceid) | string | Specifies the resource ID of connected application gateway. Required if `ingressApplicationGatewayEnabled` is set to `true`. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`aadProfileEnableAzureRBAC`](#parameter-aadprofileenableazurerbac) | bool | Specifies whether to enable Azure RBAC for Kubernetes authorization. | +| [`acrSku`](#parameter-acrsku) | string | Tier of your Azure container registry. | +| [`agentPools`](#parameter-agentpools) | array | Define one or more secondary/additional agent pools. | +| [`aksClusterRoleAssignmentName`](#parameter-aksclusterroleassignmentname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`containerRegistryRoleName`](#parameter-containerregistryrolename) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`dnsPrefix`](#parameter-dnsprefix) | string | Specifies the DNS prefix specified when creating the managed cluster. | +| [`dnsServiceIP`](#parameter-dnsserviceip) | string | Specifies the IP address assigned to the Kubernetes DNS service. It must be within the Kubernetes service address range specified in serviceCidr. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`kubernetesVersion`](#parameter-kubernetesversion) | string | Kubernetes Version. | +| [`location`](#parameter-location) | string | Specifies the location of AKS cluster. It picks up Resource Group's location by default. | +| [`monitoringWorkspaceResourceId`](#parameter-monitoringworkspaceresourceid) | string | Resource ID of the monitoring log analytics workspace. | +| [`networkDataplane`](#parameter-networkdataplane) | string | Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin. | +| [`networkPlugin`](#parameter-networkplugin) | string | Network plugin used for building the Kubernetes network. | +| [`networkPluginMode`](#parameter-networkpluginmode) | string | Network plugin mode used for building the Kubernetes network. Not compatible with kubenet network plugin. | +| [`networkPolicy`](#parameter-networkpolicy) | string | Specifies the network policy used for building Kubernetes network. - calico or azure. | +| [`nodeResourceGroupName`](#parameter-noderesourcegroupname) | string | The name of the resource group for the managed resources of the AKS cluster. | +| [`podCidr`](#parameter-podcidr) | string | Specifies the CIDR notation IP range from which to assign pod IPs when kubenet is used. | +| [`principalType`](#parameter-principaltype) | string | The type of principal to assign application roles. | +| [`publicNetworkAccess`](#parameter-publicnetworkaccess) | string | Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'. | +| [`scopeMaps`](#parameter-scopemaps) | array | Scope maps setting. | +| [`serviceCidr`](#parameter-servicecidr) | string | A CIDR notation IP range from which to assign service cluster IPs. It must not overlap with any Subnet IP ranges. | +| [`skuTier`](#parameter-skutier) | string | Tier of a managed cluster SKU. | +| [`sshPublicKey`](#parameter-sshpublickey) | string | Specifies the SSH RSA public key string for the Linux nodes. | +| [`tags`](#parameter-tags) | object | Custom tags to apply to the AKS resources. | +| [`webApplicationRoutingEnabled`](#parameter-webapplicationroutingenabled) | bool | Specifies whether the webApplicationRoutingEnabled add-on is enabled or not. | + +### Parameter: `containerRegistryName` + +Name of your Azure Container Registry. + +- Required: Yes +- Type: string + +### Parameter: `keyVaultName` + +Name of the Key Vault. Must be globally unique. + +- Required: Yes +- Type: string + +### Parameter: `logAnalyticsName` + +The name of the connected log analytics workspace. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the parent managed cluster. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `principalId` + +Id of the user or app to assign application roles. + +- Required: Yes +- Type: string + +### Parameter: `appGatewayResourceId` + +Specifies the resource ID of connected application gateway. Required if `ingressApplicationGatewayEnabled` is set to `true`. + +- Required: No +- Type: string + +### Parameter: `aadProfileEnableAzureRBAC` + +Specifies whether to enable Azure RBAC for Kubernetes authorization. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `acrSku` + +Tier of your Azure container registry. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Basic' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `agentPools` + +Define one or more secondary/additional agent pools. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-agentpoolsname) | string | The name of the agent pool. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`availabilityZones`](#parameter-agentpoolsavailabilityzones) | array | The availability zones of the agent pool. | +| [`count`](#parameter-agentpoolscount) | int | The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). | +| [`enableAutoScaling`](#parameter-agentpoolsenableautoscaling) | bool | Whether to enable auto-scaling for the agent pool. | +| [`enableDefaultTelemetry`](#parameter-agentpoolsenabledefaulttelemetry) | bool | The enable default telemetry of the agent pool. | +| [`enableEncryptionAtHost`](#parameter-agentpoolsenableencryptionathost) | bool | Whether to enable encryption at host for the agent pool. | +| [`enableFIPS`](#parameter-agentpoolsenablefips) | bool | Whether to enable FIPS for the agent pool. | +| [`enableNodePublicIP`](#parameter-agentpoolsenablenodepublicip) | bool | Whether to enable node public IP for the agent pool. | +| [`enableUltraSSD`](#parameter-agentpoolsenableultrassd) | bool | Whether to enable Ultra SSD for the agent pool. | +| [`gpuInstanceProfile`](#parameter-agentpoolsgpuinstanceprofile) | string | The GPU instance profile of the agent pool. | +| [`kubeletDiskType`](#parameter-agentpoolskubeletdisktype) | string | The kubelet disk type of the agent pool. | +| [`maxCount`](#parameter-agentpoolsmaxcount) | int | The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). | +| [`maxPods`](#parameter-agentpoolsmaxpods) | int | The maximum number of pods that can run on a node. | +| [`maxSurge`](#parameter-agentpoolsmaxsurge) | string | The maximum number of nodes that can be created during an upgrade. | +| [`minCount`](#parameter-agentpoolsmincount) | int | The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). | +| [`minPods`](#parameter-agentpoolsminpods) | int | The minimum number of pods that can run on a node. | +| [`mode`](#parameter-agentpoolsmode) | string | The mode of the agent pool. | +| [`nodeLabels`](#parameter-agentpoolsnodelabels) | object | The node labels of the agent pool. | +| [`nodePublicIpPrefixId`](#parameter-agentpoolsnodepublicipprefixid) | string | The node public IP prefix ID of the agent pool. | +| [`nodeTaints`](#parameter-agentpoolsnodetaints) | array | The node taints of the agent pool. | +| [`orchestratorVersion`](#parameter-agentpoolsorchestratorversion) | string | The Kubernetes version of the agent pool. | +| [`osDiskSizeGB`](#parameter-agentpoolsosdisksizegb) | int | The OS disk size in GB of the agent pool. | +| [`osDiskType`](#parameter-agentpoolsosdisktype) | string | The OS disk type of the agent pool. | +| [`osSku`](#parameter-agentpoolsossku) | string | The OS SKU of the agent pool. | +| [`osType`](#parameter-agentpoolsostype) | string | The OS type of the agent pool. | +| [`podSubnetId`](#parameter-agentpoolspodsubnetid) | string | The pod subnet ID of the agent pool. | +| [`proximityPlacementGroupResourceId`](#parameter-agentpoolsproximityplacementgroupresourceid) | string | The proximity placement group resource ID of the agent pool. | +| [`scaleDownMode`](#parameter-agentpoolsscaledownmode) | string | The scale down mode of the agent pool. | +| [`scaleSetEvictionPolicy`](#parameter-agentpoolsscalesetevictionpolicy) | string | The scale set eviction policy of the agent pool. | +| [`scaleSetPriority`](#parameter-agentpoolsscalesetpriority) | string | The scale set priority of the agent pool. | +| [`sourceResourceId`](#parameter-agentpoolssourceresourceid) | string | The source resource ID to create the agent pool from. | +| [`spotMaxPrice`](#parameter-agentpoolsspotmaxprice) | int | The spot max price of the agent pool. | +| [`tags`](#parameter-agentpoolstags) | object | The tags of the agent pool. | +| [`type`](#parameter-agentpoolstype) | string | The type of the agent pool. | +| [`vmSize`](#parameter-agentpoolsvmsize) | string | The VM size of the agent pool. | +| [`vnetSubnetID`](#parameter-agentpoolsvnetsubnetid) | string | The VNet subnet ID of the agent pool. | +| [`workloadRuntime`](#parameter-agentpoolsworkloadruntime) | string | The workload runtime of the agent pool. | + +### Parameter: `agentPools.name` + +The name of the agent pool. + +- Required: Yes +- Type: string + +### Parameter: `agentPools.availabilityZones` + +The availability zones of the agent pool. + +- Required: No +- Type: array + +### Parameter: `agentPools.count` + +The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). + +- Required: No +- Type: int + +### Parameter: `agentPools.enableAutoScaling` + +Whether to enable auto-scaling for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.enableDefaultTelemetry` + +The enable default telemetry of the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.enableEncryptionAtHost` + +Whether to enable encryption at host for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.enableFIPS` + +Whether to enable FIPS for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.enableNodePublicIP` + +Whether to enable node public IP for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.enableUltraSSD` + +Whether to enable Ultra SSD for the agent pool. + +- Required: No +- Type: bool + +### Parameter: `agentPools.gpuInstanceProfile` + +The GPU instance profile of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'MIG1g' + 'MIG2g' + 'MIG3g' + 'MIG4g' + 'MIG7g' + ] + ``` + +### Parameter: `agentPools.kubeletDiskType` + +The kubelet disk type of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.maxCount` + +The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). + +- Required: No +- Type: int + +### Parameter: `agentPools.maxPods` + +The maximum number of pods that can run on a node. + +- Required: No +- Type: int + +### Parameter: `agentPools.maxSurge` + +The maximum number of nodes that can be created during an upgrade. + +- Required: No +- Type: string + +### Parameter: `agentPools.minCount` + +The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive). + +- Required: No +- Type: int + +### Parameter: `agentPools.minPods` + +The minimum number of pods that can run on a node. + +- Required: No +- Type: int + +### Parameter: `agentPools.mode` + +The mode of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'System' + 'User' + ] + ``` + +### Parameter: `agentPools.nodeLabels` + +The node labels of the agent pool. + +- Required: No +- Type: object + +### Parameter: `agentPools.nodePublicIpPrefixId` + +The node public IP prefix ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.nodeTaints` + +The node taints of the agent pool. + +- Required: No +- Type: array + +### Parameter: `agentPools.orchestratorVersion` + +The Kubernetes version of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.osDiskSizeGB` + +The OS disk size in GB of the agent pool. + +- Required: No +- Type: int + +### Parameter: `agentPools.osDiskType` + +The OS disk type of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.osSku` + +The OS SKU of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.osType` + +The OS type of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Linux' + 'Windows' + ] + ``` + +### Parameter: `agentPools.podSubnetId` + +The pod subnet ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.proximityPlacementGroupResourceId` + +The proximity placement group resource ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.scaleDownMode` + +The scale down mode of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Deallocate' + 'Delete' + ] + ``` + +### Parameter: `agentPools.scaleSetEvictionPolicy` + +The scale set eviction policy of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Deallocate' + 'Delete' + ] + ``` + +### Parameter: `agentPools.scaleSetPriority` + +The scale set priority of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Low' + 'Regular' + 'Spot' + ] + ``` + +### Parameter: `agentPools.sourceResourceId` + +The source resource ID to create the agent pool from. + +- Required: No +- Type: string + +### Parameter: `agentPools.spotMaxPrice` + +The spot max price of the agent pool. + +- Required: No +- Type: int + +### Parameter: `agentPools.tags` + +The tags of the agent pool. + +- Required: No +- Type: object + +### Parameter: `agentPools.type` + +The type of the agent pool. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AvailabilitySet' + 'VirtualMachineScaleSets' + ] + ``` + +### Parameter: `agentPools.vmSize` + +The VM size of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.vnetSubnetID` + +The VNet subnet ID of the agent pool. + +- Required: No +- Type: string + +### Parameter: `agentPools.workloadRuntime` + +The workload runtime of the agent pool. + +- Required: No +- Type: string + +### Parameter: `aksClusterRoleAssignmentName` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `containerRegistryRoleName` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `dnsPrefix` + +Specifies the DNS prefix specified when creating the managed cluster. + +- Required: No +- Type: string +- Default: `[parameters('name')]` + +### Parameter: `dnsServiceIP` + +Specifies the IP address assigned to the Kubernetes DNS service. It must be within the Kubernetes service address range specified in serviceCidr. + +- Required: No +- Type: string + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `kubernetesVersion` + +Kubernetes Version. + +- Required: No +- Type: string +- Default: `'1.29'` + +### Parameter: `location` + +Specifies the location of AKS cluster. It picks up Resource Group's location by default. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `monitoringWorkspaceResourceId` + +Resource ID of the monitoring log analytics workspace. + +- Required: No +- Type: string + +### Parameter: `networkDataplane` + +Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'azure' + 'cilium' + ] + ``` + +### Parameter: `networkPlugin` + +Network plugin used for building the Kubernetes network. + +- Required: No +- Type: string +- Default: `'azure'` +- Allowed: + ```Bicep + [ + 'azure' + 'kubenet' + ] + ``` + +### Parameter: `networkPluginMode` + +Network plugin mode used for building the Kubernetes network. Not compatible with kubenet network plugin. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'overlay' + ] + ``` + +### Parameter: `networkPolicy` + +Specifies the network policy used for building Kubernetes network. - calico or azure. + +- Required: No +- Type: string +- Default: `'azure'` +- Allowed: + ```Bicep + [ + 'azure' + 'calico' + ] + ``` + +### Parameter: `nodeResourceGroupName` + +The name of the resource group for the managed resources of the AKS cluster. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `podCidr` + +Specifies the CIDR notation IP range from which to assign pod IPs when kubenet is used. + +- Required: No +- Type: string + +### Parameter: `principalType` + +The type of principal to assign application roles. + +- Required: No +- Type: string +- Default: `'User'` +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `publicNetworkAccess` + +Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `scopeMaps` + +Scope maps setting. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`actions`](#parameter-scopemapsactions) | array | The list of scoped permissions for registry artifacts. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`description`](#parameter-scopemapsdescription) | string | The user friendly description of the scope map. | +| [`name`](#parameter-scopemapsname) | string | The name of the scope map. | + +### Parameter: `scopeMaps.actions` + +The list of scoped permissions for registry artifacts. + +- Required: Yes +- Type: array + +### Parameter: `scopeMaps.description` + +The user friendly description of the scope map. + +- Required: No +- Type: string + +### Parameter: `scopeMaps.name` + +The name of the scope map. + +- Required: No +- Type: string + +### Parameter: `serviceCidr` + +A CIDR notation IP range from which to assign service cluster IPs. It must not overlap with any Subnet IP ranges. + +- Required: No +- Type: string + +### Parameter: `skuTier` + +Tier of a managed cluster SKU. + +- Required: No +- Type: string +- Default: `'Standard'` +- Allowed: + ```Bicep + [ + 'Free' + 'Premium' + 'Standard' + ] + ``` + +### Parameter: `sshPublicKey` + +Specifies the SSH RSA public key string for the Linux nodes. + +- Required: No +- Type: string + +### Parameter: `tags` + +Custom tags to apply to the AKS resources. + +- Required: No +- Type: object +- Default: `{}` + +### Parameter: `webApplicationRoutingEnabled` + +Specifies whether the webApplicationRoutingEnabled add-on is enabled or not. + +- Required: No +- Type: bool + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `containerRegistryLoginServer` | string | The login server for the container registry. | +| `containerRegistryName` | string | The resource name of the ACR. | +| `managedClusterClientId` | string | The Client ID of the AKS identity. | +| `managedClusterName` | string | The resource name of the AKS cluster. | +| `managedClusterObjectId` | string | The Object ID of the AKS identity. | +| `managedClusterResourceId` | string | The resource ID of the AKS cluster. | +| `resourceGroupName` | string | The resource group the application insights components were deployed into. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/res/container-registry/registry:0.4.0` | Remote reference | +| `br/public:avm/res/container-service/managed-cluster:0.3.0` | Remote reference | +| `br/public:avm/res/key-vault/vault:0.7.1` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/ptn/azd/aks/main.bicep b/avm/ptn/azd/aks/main.bicep new file mode 100644 index 0000000000..799530cbed --- /dev/null +++ b/avm/ptn/azd/aks/main.bicep @@ -0,0 +1,466 @@ +metadata name = 'Azd AKS' +metadata description = '''Creates an Azure Kubernetes Service (AKS) cluster with a system agent pool as well as an additional user agent pool. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the parent managed cluster. Required if the template is used in a standalone deployment.') +param name string + +@description('Required. Name of your Azure Container Registry.') +@minLength(5) +@maxLength(50) +param containerRegistryName string + +@description('Required. The name of the connected log analytics workspace.') +param logAnalyticsName string + +@description('Required. Name of the Key Vault. Must be globally unique.') +@maxLength(24) +param keyVaultName string + +@description('Optional. Specifies the location of AKS cluster. It picks up Resource Group\'s location by default.') +param location string = resourceGroup().location + +@description('Optional. Custom tags to apply to the AKS resources.') +param tags object = {} + +@description('Optional. Network plugin used for building the Kubernetes network.') +@allowed(['azure', 'kubenet']) +param networkPlugin string = 'azure' + +@description('Optional. Specifies the network policy used for building Kubernetes network. - calico or azure.') +@allowed(['azure', 'calico']) +param networkPolicy string = 'azure' + +@description('Optional. Specifies the DNS prefix specified when creating the managed cluster.') +param dnsPrefix string = name + +@description('Optional. The name of the resource group for the managed resources of the AKS cluster.') +param nodeResourceGroupName string = '' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +@description('Required. Id of the user or app to assign application roles.') +param principalId string + +@description('Optional. The type of principal to assign application roles.') +@allowed(['Device', 'ForeignGroup', 'Group', 'ServicePrincipal', 'User']) +param principalType string = 'User' + +@description('Optional. Kubernetes Version.') +param kubernetesVersion string = '1.29' + +@description('Optional. Tier of a managed cluster SKU.') +@allowed([ + 'Free' + 'Premium' + 'Standard' +]) +param skuTier string = 'Standard' + +@description('Optional. Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin.') +@allowed([ + 'azure' + 'cilium' +]) +param networkDataplane string? + +@description('Optional. Network plugin mode used for building the Kubernetes network. Not compatible with kubenet network plugin.') +@allowed([ + 'overlay' +]) +param networkPluginMode string? + +@description('Optional. Specifies the CIDR notation IP range from which to assign pod IPs when kubenet is used.') +param podCidr string? + +@description('Optional. A CIDR notation IP range from which to assign service cluster IPs. It must not overlap with any Subnet IP ranges.') +param serviceCidr string? + +@description('Optional. Specifies the IP address assigned to the Kubernetes DNS service. It must be within the Kubernetes service address range specified in serviceCidr.') +param dnsServiceIP string? + +@description('Optional. Specifies the SSH RSA public key string for the Linux nodes.') +param sshPublicKey string? + +@description('Optional. Specifies whether to enable Azure RBAC for Kubernetes authorization.') +param aadProfileEnableAzureRBAC bool = false + +@description('Conditional. Specifies the resource ID of connected application gateway. Required if `ingressApplicationGatewayEnabled` is set to `true`.') +param appGatewayResourceId string? + +@description('Optional. Resource ID of the monitoring log analytics workspace.') +param monitoringWorkspaceResourceId string? + +@description('Optional. Define one or more secondary/additional agent pools.') +param agentPools agentPoolType + +@description('Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the \'acrSku\' to be \'Premium\'.') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = 'Enabled' + +@description('Optional. Scope maps setting.') +param scopeMaps scopeMapsType + +@description('Optional. Specifies whether the webApplicationRoutingEnabled add-on is enabled or not.') +param webApplicationRoutingEnabled bool? + +@description('Optional. Tier of your Azure container registry.') +@allowed([ + 'Basic' + 'Premium' + 'Standard' +]) +param acrSku string = 'Standard' + +@description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') +param containerRegistryRoleName string? + +@description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') +param aksClusterRoleAssignmentName string? + +var aksClusterAdminRole = subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b' +) + +var acrPullRole = subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '7f951dda-4ed3-4680-a7ca-43fe172d538d' +) + +var nodePoolPresets = { + vmSize: 'Standard_DS2_v2' + count: 3 + minCount: 3 + maxCount: 5 + enableAutoScaling: true + availabilityZones: [ + '1' + '2' + '3' + ] +} + +var nodePoolBase = { + osType: 'Linux' + maxPods: 30 + type: 'VirtualMachineScaleSets' + upgradeSettings: { + maxSurge: '33%' + } +} + +var primaryAgentPoolProfile = [ + union({ name: 'npsystem', mode: 'System' }, nodePoolBase, nodePoolPresets) +] + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.azd-aks.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2021-12-01-preview' existing = if (!empty(logAnalyticsName)) { + name: logAnalyticsName +} + +module managedCluster 'br/public:avm/res/container-service/managed-cluster:0.3.0' = { + name: '${uniqueString(deployment().name, location)}-managed-cluster' + params: { + name: name + location: location + tags: tags + nodeResourceGroup: nodeResourceGroupName + networkDataplane: networkDataplane + networkPlugin: networkPlugin + networkPluginMode: networkPluginMode + networkPolicy: networkPolicy + podCidr: podCidr + serviceCidr: serviceCidr + dnsServiceIP: dnsServiceIP + kubernetesVersion: kubernetesVersion + sshPublicKey: sshPublicKey + aadProfileEnableAzureRBAC: aadProfileEnableAzureRBAC + skuTier: skuTier + appGatewayResourceId: appGatewayResourceId + monitoringWorkspaceId: monitoringWorkspaceResourceId + managedIdentities: { + systemAssigned: true + } + diagnosticSettings: [ + { + logCategoriesAndGroups: [ + { + category: 'cluster-autoscaler' + enabled: true + } + { + category: 'kube-controller-manager' + enabled: true + } + { + category: 'kube-audit-admin' + enabled: true + } + { + category: 'guard' + enabled: true + } + ] + workspaceResourceId: !empty(logAnalyticsName) ? logAnalytics.id : '' + metricCategories: [ + { + category: 'AllMetrics' + enabled: true + } + ] + } + ] + webApplicationRoutingEnabled: webApplicationRoutingEnabled + primaryAgentPoolProfile: primaryAgentPoolProfile + dnsPrefix: dnsPrefix + agentPools: agentPools + enableTelemetry: enableTelemetry + roleAssignments: [ + { + name: aksClusterRoleAssignmentName + principalId: principalId + principalType: principalType + roleDefinitionIdOrName: aksClusterAdminRole + } + ] + } +} + +module containerRegistry 'br/public:avm/res/container-registry/registry:0.4.0' = { + name: '${uniqueString(deployment().name, location)}-container-registry' + params: { + name: containerRegistryName + location: location + tags: tags + publicNetworkAccess: publicNetworkAccess + scopeMaps: scopeMaps + acrSku: acrSku + enableTelemetry: enableTelemetry + diagnosticSettings: [ + { + logCategoriesAndGroups: [ + { + category: 'ContainerRegistryRepositoryEvents' + enabled: true + } + { + category: 'ContainerRegistryLoginEvents' + enabled: true + } + ] + workspaceResourceId: !empty(logAnalyticsName) ? logAnalytics.id : '' + metricCategories: [ + { + category: 'AllMetrics' + enabled: true + } + ] + } + ] + roleAssignments: [ + { + name: containerRegistryRoleName + principalId: managedCluster.outputs.kubeletIdentityObjectId + roleDefinitionIdOrName: acrPullRole + } + ] + } +} + +module keyVault 'br/public:avm/res/key-vault/vault:0.7.1' = { + name: '${uniqueString(deployment().name, location)}-key-vault' + params: { + name: keyVaultName + enableTelemetry: enableTelemetry + accessPolicies: [ + { + objectId: managedCluster.outputs.kubeletIdentityObjectId + permissions: { + secrets: ['get', 'list'] + } + } + ] + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The resource group the application insights components were deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The resource name of the AKS cluster.') +output managedClusterName string = managedCluster.outputs.name + +@description('The Client ID of the AKS identity.') +output managedClusterClientId string = managedCluster.outputs.kubeletIdentityClientId + +@description('The Object ID of the AKS identity.') +output managedClusterObjectId string = managedCluster.outputs.kubeletIdentityObjectId + +@description('The resource ID of the AKS cluster.') +output managedClusterResourceId string = managedCluster.outputs.kubeletIdentityResourceId + +@description('The resource name of the ACR.') +output containerRegistryName string = containerRegistry.outputs.name + +@description('The login server for the container registry.') +output containerRegistryLoginServer string = containerRegistry.outputs.loginServer + +// =============== // +// Definitions // +// =============== // + +type agentPoolType = { + @description('Required. The name of the agent pool.') + name: string + + @description('Optional. The availability zones of the agent pool.') + availabilityZones: string[]? + + @description('Optional. The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive).') + count: int? + + @description('Optional. The source resource ID to create the agent pool from.') + sourceResourceId: string? + + @description('Optional. Whether to enable auto-scaling for the agent pool.') + enableAutoScaling: bool? + + @description('Optional. Whether to enable encryption at host for the agent pool.') + enableEncryptionAtHost: bool? + + @description('Optional. Whether to enable FIPS for the agent pool.') + enableFIPS: bool? + + @description('Optional. Whether to enable node public IP for the agent pool.') + enableNodePublicIP: bool? + + @description('Optional. Whether to enable Ultra SSD for the agent pool.') + enableUltraSSD: bool? + + @description('Optional. The GPU instance profile of the agent pool.') + gpuInstanceProfile: ('MIG1g' | 'MIG2g' | 'MIG3g' | 'MIG4g' | 'MIG7g')? + + @description('Optional. The kubelet disk type of the agent pool.') + kubeletDiskType: string? + + @description('Optional. The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive).') + maxCount: int? + + @description('Optional. The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive).') + minCount: int? + + @description('Optional. The maximum number of pods that can run on a node.') + maxPods: int? + + @description('Optional. The minimum number of pods that can run on a node.') + minPods: int? + + @description('Optional. The mode of the agent pool.') + mode: ('System' | 'User')? + + @description('Optional. The node labels of the agent pool.') + nodeLabels: object? + + @description('Optional. The node public IP prefix ID of the agent pool.') + nodePublicIpPrefixId: string? + + @description('Optional. The node taints of the agent pool.') + nodeTaints: string[]? + + @description('Optional. The Kubernetes version of the agent pool.') + orchestratorVersion: string? + + @description('Optional. The OS disk size in GB of the agent pool.') + osDiskSizeGB: int? + + @description('Optional. The OS disk type of the agent pool.') + osDiskType: string? + + @description('Optional. The OS SKU of the agent pool.') + osSku: string? + + @description('Optional. The OS type of the agent pool.') + osType: ('Linux' | 'Windows')? + + @description('Optional. The pod subnet ID of the agent pool.') + podSubnetId: string? + + @description('Optional. The proximity placement group resource ID of the agent pool.') + proximityPlacementGroupResourceId: string? + + @description('Optional. The scale down mode of the agent pool.') + scaleDownMode: ('Delete' | 'Deallocate')? + + @description('Optional. The scale set eviction policy of the agent pool.') + scaleSetEvictionPolicy: ('Delete' | 'Deallocate')? + + @description('Optional. The scale set priority of the agent pool.') + scaleSetPriority: ('Low' | 'Regular' | 'Spot')? + + @description('Optional. The spot max price of the agent pool.') + spotMaxPrice: int? + + @description('Optional. The tags of the agent pool.') + tags: object? + + @description('Optional. The type of the agent pool.') + type: ('AvailabilitySet' | 'VirtualMachineScaleSets')? + + @description('Optional. The maximum number of nodes that can be created during an upgrade.') + maxSurge: string? + + @description('Optional. The VM size of the agent pool.') + vmSize: string? + + @description('Optional. The VNet subnet ID of the agent pool.') + vnetSubnetID: string? + + @description('Optional. The workload runtime of the agent pool.') + workloadRuntime: string? + + @description('Optional. The enable default telemetry of the agent pool.') + enableDefaultTelemetry: bool? +}[]? + +type scopeMapsType = { + @description('Optional. The name of the scope map.') + name: string? + + @description('Required. The list of scoped permissions for registry artifacts.') + actions: string[] + + @description('Optional. The user friendly description of the scope map.') + description: string? +}[]? diff --git a/avm/ptn/azd/aks/main.json b/avm/ptn/azd/aks/main.json new file mode 100644 index 0000000000..ea34740356 --- /dev/null +++ b/avm/ptn/azd/aks/main.json @@ -0,0 +1,9163 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "1486388262618258805" + }, + "name": "Azd AKS", + "description": "Creates an Azure Kubernetes Service (AKS) cluster with a system agent pool as well as an additional user agent pool.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "agentPoolType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the agent pool." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The availability zones of the agent pool." + } + }, + "count": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "sourceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source resource ID to create the agent pool from." + } + }, + "enableAutoScaling": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable auto-scaling for the agent pool." + } + }, + "enableEncryptionAtHost": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable encryption at host for the agent pool." + } + }, + "enableFIPS": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable FIPS for the agent pool." + } + }, + "enableNodePublicIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable node public IP for the agent pool." + } + }, + "enableUltraSSD": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable Ultra SSD for the agent pool." + } + }, + "gpuInstanceProfile": { + "type": "string", + "allowedValues": [ + "MIG1g", + "MIG2g", + "MIG3g", + "MIG4g", + "MIG7g" + ], + "nullable": true, + "metadata": { + "description": "Optional. The GPU instance profile of the agent pool." + } + }, + "kubeletDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The kubelet disk type of the agent pool." + } + }, + "maxCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "minCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "maxPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of pods that can run on a node." + } + }, + "minPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of pods that can run on a node." + } + }, + "mode": { + "type": "string", + "allowedValues": [ + "System", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The mode of the agent pool." + } + }, + "nodeLabels": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The node labels of the agent pool." + } + }, + "nodePublicIpPrefixId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The node public IP prefix ID of the agent pool." + } + }, + "nodeTaints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The node taints of the agent pool." + } + }, + "orchestratorVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Kubernetes version of the agent pool." + } + }, + "osDiskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The OS disk size in GB of the agent pool." + } + }, + "osDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The OS disk type of the agent pool." + } + }, + "osSku": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The OS SKU of the agent pool." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "nullable": true, + "metadata": { + "description": "Optional. The OS type of the agent pool." + } + }, + "podSubnetId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The pod subnet ID of the agent pool." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The proximity placement group resource ID of the agent pool." + } + }, + "scaleDownMode": { + "type": "string", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale down mode of the agent pool." + } + }, + "scaleSetEvictionPolicy": { + "type": "string", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale set eviction policy of the agent pool." + } + }, + "scaleSetPriority": { + "type": "string", + "allowedValues": [ + "Low", + "Regular", + "Spot" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale set priority of the agent pool." + } + }, + "spotMaxPrice": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The spot max price of the agent pool." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the agent pool." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "AvailabilitySet", + "VirtualMachineScaleSets" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the agent pool." + } + }, + "maxSurge": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of nodes that can be created during an upgrade." + } + }, + "vmSize": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The VM size of the agent pool." + } + }, + "vnetSubnetID": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The VNet subnet ID of the agent pool." + } + }, + "workloadRuntime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The workload runtime of the agent pool." + } + }, + "enableDefaultTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The enable default telemetry of the agent pool." + } + } + } + }, + "nullable": true + }, + "scopeMapsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent managed cluster. Required if the template is used in a standalone deployment." + } + }, + "containerRegistryName": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure Container Registry." + } + }, + "logAnalyticsName": { + "type": "string", + "metadata": { + "description": "Required. The name of the connected log analytics workspace." + } + }, + "keyVaultName": { + "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. Specifies the location of AKS cluster. It picks up Resource Group's location by default." + } + }, + "tags": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Custom tags to apply to the AKS resources." + } + }, + "networkPlugin": { + "type": "string", + "defaultValue": "azure", + "allowedValues": [ + "azure", + "kubenet" + ], + "metadata": { + "description": "Optional. Network plugin used for building the Kubernetes network." + } + }, + "networkPolicy": { + "type": "string", + "defaultValue": "azure", + "allowedValues": [ + "azure", + "calico" + ], + "metadata": { + "description": "Optional. Specifies the network policy used for building Kubernetes network. - calico or azure." + } + }, + "dnsPrefix": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Specifies the DNS prefix specified when creating the managed cluster." + } + }, + "nodeResourceGroupName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the resource group for the managed resources of the AKS cluster." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. Id of the user or app to assign application roles." + } + }, + "principalType": { + "type": "string", + "defaultValue": "User", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "metadata": { + "description": "Optional. The type of principal to assign application roles." + } + }, + "kubernetesVersion": { + "type": "string", + "defaultValue": "1.29", + "metadata": { + "description": "Optional. Kubernetes Version." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of a managed cluster SKU." + } + }, + "networkDataplane": { + "type": "string", + "nullable": true, + "allowedValues": [ + "azure", + "cilium" + ], + "metadata": { + "description": "Optional. Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin." + } + }, + "networkPluginMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "overlay" + ], + "metadata": { + "description": "Optional. Network plugin mode used for building the Kubernetes network. Not compatible with kubenet network plugin." + } + }, + "podCidr": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the CIDR notation IP range from which to assign pod IPs when kubenet is used." + } + }, + "serviceCidr": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A CIDR notation IP range from which to assign service cluster IPs. It must not overlap with any Subnet IP ranges." + } + }, + "dnsServiceIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the IP address assigned to the Kubernetes DNS service. It must be within the Kubernetes service address range specified in serviceCidr." + } + }, + "sshPublicKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the SSH RSA public key string for the Linux nodes." + } + }, + "aadProfileEnableAzureRBAC": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether to enable Azure RBAC for Kubernetes authorization." + } + }, + "appGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Specifies the resource ID of connected application gateway. Required if `ingressApplicationGatewayEnabled` is set to `true`." + } + }, + "monitoringWorkspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the monitoring log analytics workspace." + } + }, + "agentPools": { + "$ref": "#/definitions/agentPoolType", + "metadata": { + "description": "Optional. Define one or more secondary/additional agent pools." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "scopeMaps": { + "$ref": "#/definitions/scopeMapsType", + "metadata": { + "description": "Optional. Scope maps setting." + } + }, + "webApplicationRoutingEnabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether the webApplicationRoutingEnabled add-on is enabled or not." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "containerRegistryRoleName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "aksClusterRoleAssignmentName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + } + }, + "variables": { + "aksClusterAdminRole": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b')]", + "acrPullRole": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "nodePoolPresets": { + "vmSize": "Standard_DS2_v2", + "count": 3, + "minCount": 3, + "maxCount": 5, + "enableAutoScaling": true, + "availabilityZones": [ + "1", + "2", + "3" + ] + }, + "nodePoolBase": { + "osType": "Linux", + "maxPods": 30, + "type": "VirtualMachineScaleSets", + "upgradeSettings": { + "maxSurge": "33%" + } + }, + "primaryAgentPoolProfile": [ + "[union(createObject('name', 'npsystem', 'mode', 'System'), variables('nodePoolBase'), variables('nodePoolPresets'))]" + ] + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-aks.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "logAnalytics": { + "condition": "[not(empty(parameters('logAnalyticsName')))]", + "existing": true, + "type": "Microsoft.OperationalInsights/workspaces", + "apiVersion": "2021-12-01-preview", + "name": "[parameters('logAnalyticsName')]" + }, + "managedCluster": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-managed-cluster', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "nodeResourceGroup": { + "value": "[parameters('nodeResourceGroupName')]" + }, + "networkDataplane": { + "value": "[parameters('networkDataplane')]" + }, + "networkPlugin": { + "value": "[parameters('networkPlugin')]" + }, + "networkPluginMode": { + "value": "[parameters('networkPluginMode')]" + }, + "networkPolicy": { + "value": "[parameters('networkPolicy')]" + }, + "podCidr": { + "value": "[parameters('podCidr')]" + }, + "serviceCidr": { + "value": "[parameters('serviceCidr')]" + }, + "dnsServiceIP": { + "value": "[parameters('dnsServiceIP')]" + }, + "kubernetesVersion": { + "value": "[parameters('kubernetesVersion')]" + }, + "sshPublicKey": { + "value": "[parameters('sshPublicKey')]" + }, + "aadProfileEnableAzureRBAC": { + "value": "[parameters('aadProfileEnableAzureRBAC')]" + }, + "skuTier": { + "value": "[parameters('skuTier')]" + }, + "appGatewayResourceId": { + "value": "[parameters('appGatewayResourceId')]" + }, + "monitoringWorkspaceId": { + "value": "[parameters('monitoringWorkspaceResourceId')]" + }, + "managedIdentities": { + "value": { + "systemAssigned": true + } + }, + "diagnosticSettings": { + "value": [ + { + "logCategoriesAndGroups": [ + { + "category": "cluster-autoscaler", + "enabled": true + }, + { + "category": "kube-controller-manager", + "enabled": true + }, + { + "category": "kube-audit-admin", + "enabled": true + }, + { + "category": "guard", + "enabled": true + } + ], + "workspaceResourceId": "[if(not(empty(parameters('logAnalyticsName'))), resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName')), '')]", + "metricCategories": [ + { + "category": "AllMetrics", + "enabled": true + } + ] + } + ] + }, + "webApplicationRoutingEnabled": { + "value": "[parameters('webApplicationRoutingEnabled')]" + }, + "primaryAgentPoolProfile": { + "value": "[variables('primaryAgentPoolProfile')]" + }, + "dnsPrefix": { + "value": "[parameters('dnsPrefix')]" + }, + "agentPools": { + "value": "[parameters('agentPools')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "roleAssignments": { + "value": [ + { + "name": "[parameters('aksClusterRoleAssignmentName')]", + "principalId": "[parameters('principalId')]", + "principalType": "[parameters('principalType')]", + "roleDefinitionIdOrName": "[variables('aksClusterAdminRole')]" + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "17708769259435874319" + }, + "name": "Azure Kubernetes Service (AKS) Managed Clusters", + "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "agentPoolType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The name of the agent pool." + } + }, + "availabilityZones": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The availability zones of the agent pool." + } + }, + "count": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "sourceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The source resource ID to create the agent pool from." + } + }, + "enableAutoScaling": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable auto-scaling for the agent pool." + } + }, + "enableEncryptionAtHost": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable encryption at host for the agent pool." + } + }, + "enableFIPS": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable FIPS for the agent pool." + } + }, + "enableNodePublicIP": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable node public IP for the agent pool." + } + }, + "enableUltraSSD": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Whether to enable Ultra SSD for the agent pool." + } + }, + "gpuInstanceProfile": { + "type": "string", + "allowedValues": [ + "MIG1g", + "MIG2g", + "MIG3g", + "MIG4g", + "MIG7g" + ], + "nullable": true, + "metadata": { + "description": "Optional. The GPU instance profile of the agent pool." + } + }, + "kubeletDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The kubelet disk type of the agent pool." + } + }, + "maxCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "minCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of agents (VMs) to host docker containers. Allowed values must be in the range of 1 to 100 (inclusive)." + } + }, + "maxPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of pods that can run on a node." + } + }, + "minPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of pods that can run on a node." + } + }, + "mode": { + "type": "string", + "allowedValues": [ + "System", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The mode of the agent pool." + } + }, + "nodeLabels": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The node labels of the agent pool." + } + }, + "nodePublicIpPrefixId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The node public IP prefix ID of the agent pool." + } + }, + "nodeTaints": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The node taints of the agent pool." + } + }, + "orchestratorVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Kubernetes version of the agent pool." + } + }, + "osDiskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The OS disk size in GB of the agent pool." + } + }, + "osDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The OS disk type of the agent pool." + } + }, + "osSku": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The OS SKU of the agent pool." + } + }, + "osType": { + "type": "string", + "allowedValues": [ + "Linux", + "Windows" + ], + "nullable": true, + "metadata": { + "description": "Optional. The OS type of the agent pool." + } + }, + "podSubnetId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The pod subnet ID of the agent pool." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The proximity placement group resource ID of the agent pool." + } + }, + "scaleDownMode": { + "type": "string", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale down mode of the agent pool." + } + }, + "scaleSetEvictionPolicy": { + "type": "string", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale set eviction policy of the agent pool." + } + }, + "scaleSetPriority": { + "type": "string", + "allowedValues": [ + "Low", + "Regular", + "Spot" + ], + "nullable": true, + "metadata": { + "description": "Optional. The scale set priority of the agent pool." + } + }, + "spotMaxPrice": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The spot max price of the agent pool." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The tags of the agent pool." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "AvailabilitySet", + "VirtualMachineScaleSets" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the agent pool." + } + }, + "maxSurge": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of nodes that can be created during an upgrade." + } + }, + "vmSize": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The VM size of the agent pool." + } + }, + "vnetSubnetID": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The VNet subnet ID of the agent pool." + } + }, + "workloadRuntime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The workload runtime of the agent pool." + } + }, + "enableDefaultTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. The enable default telemetry of the agent pool." + } + } + } + }, + "nullable": true + }, + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourcesIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "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 + }, + "fluxConfigurationProtectedSettingsType": { + "type": "object", + "properties": { + "sshPrivateKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The SSH private key to use for Git authentication." + } + } + }, + "nullable": true + }, + "extensionType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The name of the extension." + } + }, + "releaseNamespace": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Namespace where the extension Release must be placed." + } + }, + "targetNamespace": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Namespace where the extension will be created for an Namespace scoped extension." + } + }, + "releaseTrain": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. The release train of the extension." + } + }, + "configurationProtectedSettings": { + "$ref": "#/definitions/fluxConfigurationProtectedSettingsType", + "nullable": true, + "metadata": { + "description": "Optional. The configuration protected settings of the extension." + } + }, + "configurationSettings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The configuration settings of the extension." + } + }, + "version": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the extension." + } + }, + "configurations": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The flux configurations of the extension." + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "keyVaultNetworkAccess": { + "type": "string", + "allowedValues": [ + "Private", + "Public" + ], + "metadata": { + "description": "Required. Network access of key vault. The possible values are Public and Private. Public means the key vault allows public access from all networks. Private means the key vault disables public access and enables private link. The default value is Public." + } + } + }, + "nullable": true + }, + "maintenanceConfigurationType": { + "type": "object", + "properties": { + "maintenanceWindow": { + "type": "object", + "metadata": { + "description": "Required. Maintenance window for the maintenance configuration." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Specifies the name of the AKS cluster." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Specifies the location of AKS cluster. It picks up Resource Group's location by default." + } + }, + "dnsPrefix": { + "type": "string", + "defaultValue": "[parameters('name')]", + "metadata": { + "description": "Optional. Specifies the DNS prefix specified when creating the managed cluster." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource. Only one type of identity is supported: system-assigned or user-assigned, but not both." + } + }, + "networkDataplane": { + "type": "string", + "nullable": true, + "allowedValues": [ + "azure", + "cilium" + ], + "metadata": { + "description": "Optional. Network dataplane used in the Kubernetes cluster. Not compatible with kubenet network plugin." + } + }, + "networkPlugin": { + "type": "string", + "nullable": true, + "allowedValues": [ + "azure", + "kubenet" + ], + "metadata": { + "description": "Optional. Specifies the network plugin used for building Kubernetes network." + } + }, + "networkPluginMode": { + "type": "string", + "nullable": true, + "allowedValues": [ + "overlay" + ], + "metadata": { + "description": "Optional. Network plugin mode used for building the Kubernetes network. Not compatible with kubenet network plugin." + } + }, + "networkPolicy": { + "type": "string", + "nullable": true, + "allowedValues": [ + "azure", + "calico" + ], + "metadata": { + "description": "Optional. Specifies the network policy used for building Kubernetes network. - calico or azure." + } + }, + "podCidr": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the CIDR notation IP range from which to assign pod IPs when kubenet is used." + } + }, + "serviceCidr": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A CIDR notation IP range from which to assign service cluster IPs. It must not overlap with any Subnet IP ranges." + } + }, + "dnsServiceIP": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the IP address assigned to the Kubernetes DNS service. It must be within the Kubernetes service address range specified in serviceCidr." + } + }, + "loadBalancerSku": { + "type": "string", + "defaultValue": "standard", + "allowedValues": [ + "basic", + "standard" + ], + "metadata": { + "description": "Optional. Specifies the sku of the load balancer used by the virtual machine scale sets used by nodepools." + } + }, + "managedOutboundIPCount": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Outbound IP Count for the Load balancer." + } + }, + "backendPoolType": { + "type": "string", + "defaultValue": "NodeIPConfiguration", + "allowedValues": [ + "NodeIP", + "NodeIPConfiguration" + ], + "metadata": { + "description": "Optional. The type of the managed inbound Load Balancer BackendPool." + } + }, + "outboundType": { + "type": "string", + "defaultValue": "loadBalancer", + "allowedValues": [ + "loadBalancer", + "userDefinedRouting", + "managedNATGateway", + "userAssignedNATGateway" + ], + "metadata": { + "description": "Optional. Specifies outbound (egress) routing method." + } + }, + "skuTier": { + "type": "string", + "defaultValue": "Standard", + "allowedValues": [ + "Free", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of a managed cluster SKU." + } + }, + "kubernetesVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Version of Kubernetes specified when creating the managed cluster." + } + }, + "adminUsername": { + "type": "string", + "defaultValue": "azureuser", + "metadata": { + "description": "Optional. Specifies the administrator username of Linux virtual machines." + } + }, + "sshPublicKey": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the SSH RSA public key string for the Linux nodes." + } + }, + "aksServicePrincipalProfile": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Conditional. Information about a service principal identity for the cluster to use for manipulating Azure APIs. Required if no managed identities are assigned to the cluster." + } + }, + "aadProfileClientAppID": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The client AAD application ID." + } + }, + "aadProfileServerAppID": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The server AAD application ID." + } + }, + "aadProfileServerAppSecret": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The server AAD application secret." + } + }, + "aadProfileTenantId": { + "type": "string", + "defaultValue": "[subscription().tenantId]", + "metadata": { + "description": "Optional. Specifies the tenant ID of the Azure Active Directory used by the AKS cluster for authentication." + } + }, + "aadProfileAdminGroupObjectIDs": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the AAD group object IDs that will have admin role of the cluster." + } + }, + "aadProfileManaged": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether to enable managed AAD integration." + } + }, + "enableRBAC": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Whether to enable Kubernetes Role-Based Access Control." + } + }, + "aadProfileEnableAzureRBAC": { + "type": "bool", + "defaultValue": "[parameters('enableRBAC')]", + "metadata": { + "description": "Optional. Specifies whether to enable Azure RBAC for Kubernetes authorization." + } + }, + "disableLocalAccounts": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. If set to true, getting static credentials will be disabled for this cluster. This must only be used on Managed Clusters that are AAD enabled." + } + }, + "nodeResourceGroup": { + "type": "string", + "defaultValue": "[format('{0}_aks_{1}_nodes', resourceGroup().name, parameters('name'))]", + "metadata": { + "description": "Optional. Name of the resource group containing agent pool nodes." + } + }, + "authorizedIPRanges": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. IP ranges are specified in CIDR format, e.g. 137.117.106.88/29. This feature is not compatible with clusters that use Public IP Per Node, or clusters that are using a Basic Load Balancer." + } + }, + "disableRunCommand": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to disable run command for the cluster or not." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Enabled", + "Disabled", + "SecuredByPerimeter" + ], + "metadata": { + "description": "Optional. Allow or deny public network access for AKS." + } + }, + "enablePrivateCluster": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether to create the cluster as a private cluster or not." + } + }, + "enablePrivateClusterPublicFQDN": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to create additional public FQDN for private cluster or not." + } + }, + "privateDNSZone": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Private DNS Zone configuration. Set to 'system' and AKS will create a private DNS zone in the node resource group. Set to '' to disable private DNS Zone creation and use public DNS. Supply the resource ID here of an existing Private DNS zone to use an existing zone." + } + }, + "primaryAgentPoolProfile": { + "type": "array", + "metadata": { + "description": "Required. Properties of the primary agent pool." + } + }, + "agentPools": { + "$ref": "#/definitions/agentPoolType", + "metadata": { + "description": "Optional. Define one or more secondary/additional agent pools." + } + }, + "maintenanceConfiguration": { + "$ref": "#/definitions/maintenanceConfigurationType", + "metadata": { + "description": "Optional. Whether or not to use AKS Automatic mode." + } + }, + "costAnalysisEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the cost analysis add-on is enabled or not. If Enabled `enableStorageProfileDiskCSIDriver` is set to true as it is needed." + } + }, + "httpApplicationRoutingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the httpApplicationRouting add-on is enabled or not." + } + }, + "webApplicationRoutingEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the webApplicationRoutingEnabled add-on is enabled or not." + } + }, + "dnsZoneResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the resource ID of connected DNS zone. It will be ignored if `webApplicationRoutingEnabled` is set to `false`." + } + }, + "enableDnsZoneContributorRoleAssignment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether assing the DNS zone contributor role to the cluster service principal. It will be ignored if `webApplicationRoutingEnabled` is set to `false` or `dnsZoneResourceId` not provided." + } + }, + "ingressApplicationGatewayEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the ingressApplicationGateway (AGIC) add-on is enabled or not." + } + }, + "appGatewayResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. Specifies the resource ID of connected application gateway. Required if `ingressApplicationGatewayEnabled` is set to `true`." + } + }, + "aciConnectorLinuxEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the aciConnectorLinux add-on is enabled or not." + } + }, + "azurePolicyEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the azurepolicy add-on is enabled or not. For security reasons, this setting should be enabled." + } + }, + "openServiceMeshEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the openServiceMesh add-on is enabled or not." + } + }, + "azurePolicyVersion": { + "type": "string", + "defaultValue": "v2", + "metadata": { + "description": "Optional. Specifies the azure policy version to use." + } + }, + "kubeDashboardEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the kubeDashboard add-on is enabled or not." + } + }, + "enableKeyvaultSecretsProvider": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the KeyvaultSecretsProvider add-on is enabled or not." + } + }, + "enableSecretRotation": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies whether the KeyvaultSecretsProvider add-on uses secret rotation." + } + }, + "autoScalerProfileScanInterval": { + "type": "string", + "defaultValue": "10s", + "metadata": { + "description": "Optional. Specifies the scan interval of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileScaleDownDelayAfterAdd": { + "type": "string", + "defaultValue": "10m", + "metadata": { + "description": "Optional. Specifies the scale down delay after add of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileScaleDownDelayAfterDelete": { + "type": "string", + "defaultValue": "20s", + "metadata": { + "description": "Optional. Specifies the scale down delay after delete of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileScaleDownDelayAfterFailure": { + "type": "string", + "defaultValue": "3m", + "metadata": { + "description": "Optional. Specifies scale down delay after failure of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileScaleDownUnneededTime": { + "type": "string", + "defaultValue": "10m", + "metadata": { + "description": "Optional. Specifies the scale down unneeded time of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileScaleDownUnreadyTime": { + "type": "string", + "defaultValue": "20m", + "metadata": { + "description": "Optional. Specifies the scale down unready time of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileUtilizationThreshold": { + "type": "string", + "defaultValue": "0.5", + "metadata": { + "description": "Optional. Specifies the utilization threshold of the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileMaxGracefulTerminationSec": { + "type": "string", + "defaultValue": "600", + "metadata": { + "description": "Optional. Specifies the max graceful termination time interval in seconds for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileBalanceSimilarNodeGroups": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies the balance of similar node groups for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileExpander": { + "type": "string", + "defaultValue": "random", + "allowedValues": [ + "least-waste", + "most-pods", + "priority", + "random" + ], + "metadata": { + "description": "Optional. Specifies the expand strategy for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileMaxEmptyBulkDelete": { + "type": "string", + "defaultValue": "10", + "metadata": { + "description": "Optional. Specifies the maximum empty bulk delete for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileMaxNodeProvisionTime": { + "type": "string", + "defaultValue": "15m", + "metadata": { + "description": "Optional. Specifies the maximum node provisioning time for the auto-scaler of the AKS cluster. Values must be an integer followed by an \"m\". No unit of time other than minutes (m) is supported." + } + }, + "autoScalerProfileMaxTotalUnreadyPercentage": { + "type": "string", + "defaultValue": "45", + "metadata": { + "description": "Optional. Specifies the mximum total unready percentage for the auto-scaler of the AKS cluster. The maximum is 100 and the minimum is 0." + } + }, + "autoScalerProfileNewPodScaleUpDelay": { + "type": "string", + "defaultValue": "0s", + "metadata": { + "description": "Optional. For scenarios like burst/batch scale where you do not want CA to act before the kubernetes scheduler could schedule all the pods, you can tell CA to ignore unscheduled pods before they are a certain age. Values must be an integer followed by a unit (\"s\" for seconds, \"m\" for minutes, \"h\" for hours, etc)." + } + }, + "autoScalerProfileOkTotalUnreadyCount": { + "type": "string", + "defaultValue": "3", + "metadata": { + "description": "Optional. Specifies the OK total unready count for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileSkipNodesWithLocalStorage": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if nodes with local storage should be skipped for the auto-scaler of the AKS cluster." + } + }, + "autoScalerProfileSkipNodesWithSystemPods": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if nodes with system pods should be skipped for the auto-scaler of the AKS cluster." + } + }, + "autoUpgradeProfileUpgradeChannel": { + "type": "string", + "defaultValue": "stable", + "allowedValues": [ + "node-image", + "none", + "patch", + "rapid", + "stable" + ], + "metadata": { + "description": "Optional. Auto-upgrade channel on the AKS cluster." + } + }, + "podIdentityProfileAllowNetworkPluginKubenet": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Running in Kubenet is disabled by default due to the security related nature of AAD Pod Identity and the risks of IP spoofing." + } + }, + "podIdentityProfileEnable": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the pod identity addon is enabled." + } + }, + "podIdentityProfileUserAssignedIdentities": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The pod identities to use in the cluster." + } + }, + "podIdentityProfileUserAssignedIdentityExceptions": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The pod identity exceptions to allow." + } + }, + "enableOidcIssuerProfile": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the The OIDC issuer profile of the Managed Cluster is enabled." + } + }, + "enableWorkloadIdentity": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable Workload Identity. Requires OIDC issuer profile to be enabled." + } + }, + "enableAzureDefender": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable Azure Defender." + } + }, + "enableImageCleaner": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable Image Cleaner for Kubernetes." + } + }, + "imageCleanerIntervalHours": { + "type": "int", + "defaultValue": 24, + "minValue": 24, + "metadata": { + "description": "Optional. The interval in hours Image Cleaner will run. The maximum value is three months." + } + }, + "enablePodSecurityPolicy": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable Kubernetes pod security policy. Requires enabling the pod security policy feature flag on the subscription." + } + }, + "enableStorageProfileBlobCSIDriver": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the AzureBlob CSI Driver for the storage profile is enabled." + } + }, + "enableStorageProfileDiskCSIDriver": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the AzureDisk CSI Driver for the storage profile is enabled." + } + }, + "enableStorageProfileFileCSIDriver": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the AzureFile CSI Driver for the storage profile is enabled." + } + }, + "enableStorageProfileSnapshotController": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the snapshot controller for the storage profile is enabled." + } + }, + "supportPlan": { + "type": "string", + "defaultValue": "KubernetesOfficial", + "allowedValues": [ + "AKSLongTermSupport", + "KubernetesOfficial" + ], + "metadata": { + "description": "Optional. The support plan for the Managed Cluster." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "omsAgentEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the OMS agent is enabled." + } + }, + "monitoringWorkspaceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the monitoring log analytics workspace." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "diskEncryptionSetResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the disc encryption set to apply to the cluster. For security reasons, this value should be provided." + } + }, + "fluxExtension": { + "$ref": "#/definitions/extensionType", + "metadata": { + "description": "Optional. Settings and configurations for the flux extension." + } + }, + "httpProxyConfig": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Configurations for provisioning the cluster with HTTP proxy servers." + } + }, + "identityProfile": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Identities associated with the cluster." + } + }, + "kedaAddon": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables Kubernetes Event-driven Autoscaling (KEDA)." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "enableAzureMonitorProfileMetrics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether the metric state of the kubenetes cluster is enabled." + } + }, + "enableContainerInsights": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates if Azure Monitor Container Insights Logs Addon is enabled." + } + }, + "disableCustomMetrics": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether custom metrics collection has to be disabled or not. If not specified the default is false. No custom metrics will be emitted if this field is false but the container insights enabled field is false." + } + }, + "disablePrometheusMetricsScraping": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Indicates whether prometheus metrics scraping is disabled or not. If not specified the default is false. No prometheus metrics will be emitted if this field is false but the container insights enabled field is false." + } + }, + "syslogPort": { + "type": "int", + "defaultValue": 28330, + "metadata": { + "description": "Optional. The syslog host port. If not specified, the default port is 28330." + } + }, + "metricLabelsAllowlist": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A comma-separated list of kubernetes cluster metrics labels." + } + }, + "metricAnnotationsAllowList": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. A comma-separated list of Kubernetes cluster metrics annotations." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourcesIds'), createObject()))), 'UserAssigned', null())), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Azure Kubernetes Fleet Manager Contributor Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '63bb64ad-9799-4770-b5c3-24ed299a07bf')]", + "Azure Kubernetes Fleet Manager RBAC Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '434fb43a-c01c-447e-9f67-c3ad923cfaba')]", + "Azure Kubernetes Fleet Manager RBAC Cluster Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18ab4d3d-a1bf-4477-8ad9-8359bc988f69')]", + "Azure Kubernetes Fleet Manager RBAC Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '30b27cfc-9c84-438e-b0ce-70e35255df80')]", + "Azure Kubernetes Fleet Manager RBAC Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '5af6afb3-c06c-4fa4-8848-71a8aee05683')]", + "Azure Kubernetes Service Cluster Admin Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0ab0b1a8-8aac-4efd-b8c2-3ee1fb270be8')]", + "Azure Kubernetes Service Cluster Monitoring User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '1afdec4b-e479-420e-99e7-f82237c7c5e6')]", + "Azure Kubernetes Service Cluster User Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4abbcc35-e782-43d8-92c5-2d3f1bd2253f')]", + "Azure Kubernetes Service Contributor Role": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ed7f3fbd-7b88-4dd4-9017-9adb7ce333f8')]", + "Azure Kubernetes Service RBAC Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3498e952-d568-435e-9b2c-8d77e338d7f7')]", + "Azure Kubernetes Service RBAC Cluster Admin": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b1ff04bb-8a4e-4dc4-8eb5-8693973ce19b')]", + "Azure Kubernetes Service RBAC Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f6c6a51-bcf8-42ba-9220-52d62157d7db')]", + "Azure Kubernetes Service RBAC Writer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a7ffa36f-339b-4b5c-8bdf-e2c188b2c0eb')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Kubernetes Agentless Operator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'd5a2ae44-610b-4500-93be-660a0c5f5ca6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.containerservice-managedcluster.{0}.{1}', replace('0.3.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "managedCluster": { + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2024-03-02-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "sku": { + "name": "Base", + "tier": "[parameters('skuTier')]" + }, + "properties": { + "httpProxyConfig": "[parameters('httpProxyConfig')]", + "identityProfile": "[parameters('identityProfile')]", + "diskEncryptionSetID": "[parameters('diskEncryptionSetResourceId')]", + "kubernetesVersion": "[parameters('kubernetesVersion')]", + "dnsPrefix": "[parameters('dnsPrefix')]", + "agentPoolProfiles": "[parameters('primaryAgentPoolProfile')]", + "linuxProfile": "[if(not(empty(parameters('sshPublicKey'))), createObject('adminUsername', parameters('adminUsername'), 'ssh', createObject('publicKeys', createArray(createObject('keyData', coalesce(parameters('sshPublicKey'), ''))))), null())]", + "servicePrincipalProfile": "[parameters('aksServicePrincipalProfile')]", + "metricsProfile": { + "costAnalysis": { + "enabled": "[if(equals(parameters('skuTier'), 'free'), false(), parameters('costAnalysisEnabled'))]" + } + }, + "ingressProfile": { + "webAppRouting": { + "enabled": "[parameters('webApplicationRoutingEnabled')]", + "dnsZoneResourceIds": "[if(not(empty(parameters('dnsZoneResourceId'))), createArray(parameters('dnsZoneResourceId')), null())]" + } + }, + "addonProfiles": { + "httpApplicationRouting": { + "enabled": "[parameters('httpApplicationRoutingEnabled')]" + }, + "ingressApplicationGateway": { + "enabled": "[and(parameters('ingressApplicationGatewayEnabled'), not(empty(parameters('appGatewayResourceId'))))]", + "config": "[if(and(parameters('ingressApplicationGatewayEnabled'), not(empty(parameters('appGatewayResourceId')))), createObject('applicationGatewayId', parameters('appGatewayResourceId'), 'effectiveApplicationGatewayId', parameters('appGatewayResourceId')), null())]" + }, + "omsagent": { + "enabled": "[and(parameters('omsAgentEnabled'), not(empty(parameters('monitoringWorkspaceId'))))]", + "config": "[if(and(parameters('omsAgentEnabled'), not(empty(parameters('monitoringWorkspaceId')))), createObject('logAnalyticsWorkspaceResourceID', parameters('monitoringWorkspaceId')), null())]" + }, + "aciConnectorLinux": { + "enabled": "[parameters('aciConnectorLinuxEnabled')]" + }, + "azurepolicy": { + "enabled": "[parameters('azurePolicyEnabled')]", + "config": "[if(parameters('azurePolicyEnabled'), createObject('version', parameters('azurePolicyVersion')), null())]" + }, + "openServiceMesh": { + "enabled": "[parameters('openServiceMeshEnabled')]", + "config": "[if(parameters('openServiceMeshEnabled'), createObject(), null())]" + }, + "kubeDashboard": { + "enabled": "[parameters('kubeDashboardEnabled')]" + }, + "azureKeyvaultSecretsProvider": { + "enabled": "[parameters('enableKeyvaultSecretsProvider')]", + "config": "[if(parameters('enableKeyvaultSecretsProvider'), createObject('enableSecretRotation', toLower(string(parameters('enableSecretRotation')))), null())]" + } + }, + "oidcIssuerProfile": "[if(parameters('enableOidcIssuerProfile'), createObject('enabled', parameters('enableOidcIssuerProfile')), null())]", + "enableRBAC": "[parameters('enableRBAC')]", + "disableLocalAccounts": "[parameters('disableLocalAccounts')]", + "nodeResourceGroup": "[parameters('nodeResourceGroup')]", + "enablePodSecurityPolicy": "[parameters('enablePodSecurityPolicy')]", + "workloadAutoScalerProfile": { + "keda": { + "enabled": "[parameters('kedaAddon')]" + } + }, + "networkProfile": { + "networkDataplane": "[parameters('networkDataplane')]", + "networkPlugin": "[parameters('networkPlugin')]", + "networkPluginMode": "[parameters('networkPluginMode')]", + "networkPolicy": "[parameters('networkPolicy')]", + "podCidr": "[parameters('podCidr')]", + "serviceCidr": "[parameters('serviceCidr')]", + "dnsServiceIP": "[parameters('dnsServiceIP')]", + "outboundType": "[parameters('outboundType')]", + "loadBalancerSku": "[parameters('loadBalancerSku')]", + "loadBalancerProfile": { + "managedOutboundIPs": "[if(not(equals(parameters('managedOutboundIPCount'), 0)), createObject('count', parameters('managedOutboundIPCount')), null())]", + "effectiveOutboundIPs": [], + "backendPoolType": "[parameters('backendPoolType')]" + } + }, + "publicNetworkAccess": "[parameters('publicNetworkAccess')]", + "aadProfile": { + "clientAppID": "[parameters('aadProfileClientAppID')]", + "serverAppID": "[parameters('aadProfileServerAppID')]", + "serverAppSecret": "[parameters('aadProfileServerAppSecret')]", + "managed": "[parameters('aadProfileManaged')]", + "enableAzureRBAC": "[parameters('aadProfileEnableAzureRBAC')]", + "adminGroupObjectIDs": "[parameters('aadProfileAdminGroupObjectIDs')]", + "tenantID": "[parameters('aadProfileTenantId')]" + }, + "autoScalerProfile": { + "balance-similar-node-groups": "[toLower(string(parameters('autoScalerProfileBalanceSimilarNodeGroups')))]", + "expander": "[parameters('autoScalerProfileExpander')]", + "max-empty-bulk-delete": "[parameters('autoScalerProfileMaxEmptyBulkDelete')]", + "max-graceful-termination-sec": "[parameters('autoScalerProfileMaxGracefulTerminationSec')]", + "max-node-provision-time": "[parameters('autoScalerProfileMaxNodeProvisionTime')]", + "max-total-unready-percentage": "[parameters('autoScalerProfileMaxTotalUnreadyPercentage')]", + "new-pod-scale-up-delay": "[parameters('autoScalerProfileNewPodScaleUpDelay')]", + "ok-total-unready-count": "[parameters('autoScalerProfileOkTotalUnreadyCount')]", + "scale-down-delay-after-add": "[parameters('autoScalerProfileScaleDownDelayAfterAdd')]", + "scale-down-delay-after-delete": "[parameters('autoScalerProfileScaleDownDelayAfterDelete')]", + "scale-down-delay-after-failure": "[parameters('autoScalerProfileScaleDownDelayAfterFailure')]", + "scale-down-unneeded-time": "[parameters('autoScalerProfileScaleDownUnneededTime')]", + "scale-down-unready-time": "[parameters('autoScalerProfileScaleDownUnreadyTime')]", + "scale-down-utilization-threshold": "[parameters('autoScalerProfileUtilizationThreshold')]", + "scan-interval": "[parameters('autoScalerProfileScanInterval')]", + "skip-nodes-with-local-storage": "[toLower(string(parameters('autoScalerProfileSkipNodesWithLocalStorage')))]", + "skip-nodes-with-system-pods": "[toLower(string(parameters('autoScalerProfileSkipNodesWithSystemPods')))]" + }, + "autoUpgradeProfile": { + "upgradeChannel": "[parameters('autoUpgradeProfileUpgradeChannel')]" + }, + "apiServerAccessProfile": { + "authorizedIPRanges": "[parameters('authorizedIPRanges')]", + "disableRunCommand": "[parameters('disableRunCommand')]", + "enablePrivateCluster": "[parameters('enablePrivateCluster')]", + "enablePrivateClusterPublicFQDN": "[parameters('enablePrivateClusterPublicFQDN')]", + "privateDNSZone": "[parameters('privateDNSZone')]" + }, + "azureMonitorProfile": { + "containerInsights": "[if(parameters('enableContainerInsights'), createObject('enabled', parameters('enableContainerInsights'), 'logAnalyticsWorkspaceResourceId', if(not(empty(parameters('monitoringWorkspaceId'))), parameters('monitoringWorkspaceId'), null()), 'disableCustomMetrics', parameters('disableCustomMetrics'), 'disablePrometheusMetricsScraping', parameters('disablePrometheusMetricsScraping'), 'syslogPort', parameters('syslogPort')), null())]", + "metrics": "[if(parameters('enableAzureMonitorProfileMetrics'), createObject('enabled', parameters('enableAzureMonitorProfileMetrics'), 'kubeStateMetrics', createObject('metricLabelsAllowlist', parameters('metricLabelsAllowlist'), 'metricAnnotationsAllowList', parameters('metricAnnotationsAllowList'))), null())]" + }, + "podIdentityProfile": { + "allowNetworkPluginKubenet": "[parameters('podIdentityProfileAllowNetworkPluginKubenet')]", + "enabled": "[parameters('podIdentityProfileEnable')]", + "userAssignedIdentities": "[parameters('podIdentityProfileUserAssignedIdentities')]", + "userAssignedIdentityExceptions": "[parameters('podIdentityProfileUserAssignedIdentityExceptions')]" + }, + "securityProfile": { + "defender": "[if(parameters('enableAzureDefender'), createObject('securityMonitoring', createObject('enabled', parameters('enableAzureDefender')), 'logAnalyticsWorkspaceResourceId', parameters('monitoringWorkspaceId')), null())]", + "workloadIdentity": "[if(parameters('enableWorkloadIdentity'), createObject('enabled', parameters('enableWorkloadIdentity')), null())]", + "imageCleaner": "[if(parameters('enableImageCleaner'), createObject('enabled', parameters('enableImageCleaner'), 'intervalHours', parameters('imageCleanerIntervalHours')), null())]" + }, + "storageProfile": { + "blobCSIDriver": { + "enabled": "[parameters('enableStorageProfileBlobCSIDriver')]" + }, + "diskCSIDriver": { + "enabled": "[if(and(equals(parameters('costAnalysisEnabled'), true()), not(equals(parameters('skuTier'), 'free'))), true(), parameters('enableStorageProfileDiskCSIDriver'))]" + }, + "fileCSIDriver": { + "enabled": "[parameters('enableStorageProfileFileCSIDriver')]" + }, + "snapshotController": { + "enabled": "[parameters('enableStorageProfileSnapshotController')]" + } + }, + "supportPlan": "[parameters('supportPlan')]" + } + }, + "managedCluster_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.ContainerService/managedClusters/{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": [ + "managedCluster" + ] + }, + "managedCluster_diagnosticSettings": { + "copy": { + "name": "managedCluster_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "managedCluster" + ] + }, + "managedCluster_roleAssignments": { + "copy": { + "name": "managedCluster_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerService/managedClusters', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "managedCluster" + ] + }, + "dnsZone": { + "condition": "[and(and(equals(parameters('enableDnsZoneContributorRoleAssignment'), true()), not(equals(parameters('dnsZoneResourceId'), null()))), parameters('webApplicationRoutingEnabled'))]", + "existing": true, + "type": "Microsoft.Network/dnsZones", + "apiVersion": "2018-05-01", + "name": "[last(split(if(not(empty(parameters('dnsZoneResourceId'))), parameters('dnsZoneResourceId'), '/dummmyZone'), '/'))]" + }, + "dnsZone_roleAssignment": { + "condition": "[and(and(equals(parameters('enableDnsZoneContributorRoleAssignment'), true()), not(equals(parameters('dnsZoneResourceId'), null()))), parameters('webApplicationRoutingEnabled'))]", + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/dnsZones/{0}', last(split(if(not(empty(parameters('dnsZoneResourceId'))), parameters('dnsZoneResourceId'), '/dummmyZone'), '/')))]", + "name": "[guid(resourceId('Microsoft.Network/dnsZones', last(split(if(not(empty(parameters('dnsZoneResourceId'))), parameters('dnsZoneResourceId'), '/dummmyZone'), '/'))), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314'), 'DNS Zone Contributor')]", + "properties": { + "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "principalId": "[reference('managedCluster').ingressProfile.webAppRouting.identity.objectId]", + "principalType": "ServicePrincipal" + }, + "dependsOn": [ + "dnsZone", + "managedCluster" + ] + }, + "managedCluster_maintenanceConfigurations": { + "condition": "[not(empty(parameters('maintenanceConfiguration')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ManagedCluster-MaintenanceConfigurations', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "maintenanceWindow": { + "value": "[parameters('maintenanceConfiguration').maintenanceWindow]" + }, + "managedClusterName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "12168542117744033419" + }, + "name": "Azure Kubernetes Service (AKS) Managed Cluster Maintenance Configurations", + "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster Maintenance Configurations.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "maintenanceWindow": { + "type": "object", + "metadata": { + "description": "Required. Maintenance window for the maintenance configuration." + } + }, + "managedClusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent managed cluster. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "aksManagedAutoUpgradeSchedule", + "metadata": { + "description": "Optional. Name of the maintenance configuration." + } + } + }, + "resources": [ + { + "type": "Microsoft.ContainerService/managedClusters/maintenanceConfigurations", + "apiVersion": "2023-10-01", + "name": "[format('{0}/{1}', parameters('managedClusterName'), parameters('name'))]", + "properties": { + "maintenanceWindow": "[parameters('maintenanceWindow')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the maintenance configuration." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the maintenance configuration." + }, + "value": "[resourceId('Microsoft.ContainerService/managedClusters/maintenanceConfigurations', parameters('managedClusterName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "managedCluster" + ] + }, + "managedCluster_agentPools": { + "copy": { + "name": "managedCluster_agentPools", + "count": "[length(coalesce(parameters('agentPools'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ManagedCluster-AgentPool-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "managedClusterName": { + "value": "[parameters('name')]" + }, + "name": { + "value": "[coalesce(parameters('agentPools'), createArray())[copyIndex()].name]" + }, + "availabilityZones": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'availabilityZones')]" + }, + "count": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'count')]" + }, + "sourceResourceId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'sourceResourceId')]" + }, + "enableAutoScaling": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'enableAutoScaling')]" + }, + "enableEncryptionAtHost": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'enableEncryptionAtHost')]" + }, + "enableFIPS": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'enableFIPS')]" + }, + "enableNodePublicIP": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'enableNodePublicIP')]" + }, + "enableUltraSSD": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'enableUltraSSD')]" + }, + "gpuInstanceProfile": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'gpuInstanceProfile')]" + }, + "kubeletDiskType": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'kubeletDiskType')]" + }, + "maxCount": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'maxCount')]" + }, + "maxPods": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'maxPods')]" + }, + "minCount": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'minCount')]" + }, + "mode": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'mode')]" + }, + "nodeLabels": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'nodeLabels')]" + }, + "nodePublicIpPrefixId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'nodePublicIpPrefixId')]" + }, + "nodeTaints": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'nodeTaints')]" + }, + "orchestratorVersion": { + "value": "[coalesce(tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'orchestratorVersion'), parameters('kubernetesVersion'))]" + }, + "osDiskSizeGB": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'osDiskSizeGB')]" + }, + "osDiskType": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'osDiskType')]" + }, + "osSku": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'osSku')]" + }, + "osType": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'osType')]" + }, + "podSubnetId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'podSubnetId')]" + }, + "proximityPlacementGroupResourceId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'proximityPlacementGroupResourceId')]" + }, + "scaleDownMode": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'scaleDownMode')]" + }, + "scaleSetEvictionPolicy": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'scaleSetEvictionPolicy')]" + }, + "scaleSetPriority": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'scaleSetPriority')]" + }, + "spotMaxPrice": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'spotMaxPrice')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "type": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'type')]" + }, + "maxSurge": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'maxSurge')]" + }, + "vmSize": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'vmSize')]" + }, + "vnetSubnetId": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'vnetSubnetId')]" + }, + "workloadRuntime": { + "value": "[tryGet(coalesce(parameters('agentPools'), createArray())[copyIndex()], 'workloadRuntime')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "2004205618690542488" + }, + "name": "Azure Kubernetes Service (AKS) Managed Cluster Agent Pools", + "description": "This module deploys an Azure Kubernetes Service (AKS) Managed Cluster Agent Pool.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "managedClusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent managed cluster. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the agent pool." + } + }, + "availabilityZones": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The list of Availability zones to use for nodes. This can only be specified if the AgentPoolType property is \"VirtualMachineScaleSets\"." + } + }, + "count": { + "type": "int", + "defaultValue": 1, + "minValue": 0, + "maxValue": 1000, + "metadata": { + "description": "Optional. Desired Number of agents (VMs) specified to host docker containers. Allowed values must be in the range of 0 to 1000 (inclusive) for user pools and in the range of 1 to 1000 (inclusive) for system pools. The default value is 1." + } + }, + "sourceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This is the ARM ID of the source object to be used to create the target object." + } + }, + "enableAutoScaling": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable auto-scaler." + } + }, + "enableEncryptionAtHost": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. This is only supported on certain VM sizes and in certain Azure regions. For more information, see: /azure/aks/enable-host-encryption. For security reasons, this setting should be enabled." + } + }, + "enableFIPS": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. See Add a FIPS-enabled node pool (https://learn.microsoft.com/en-us/azure/aks/use-multiple-node-pools#add-a-fips-enabled-node-pool-preview) for more details." + } + }, + "enableNodePublicIP": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Some scenarios may require nodes in a node pool to receive their own dedicated public IP addresses. A common scenario is for gaming workloads, where a console needs to make a direct connection to a cloud virtual machine to minimize hops. For more information see assigning a public IP per node (https://learn.microsoft.com/en-us/azure/aks/use-multiple-node-pools#assign-a-public-ip-per-node-for-your-node-pools)." + } + }, + "enableUltraSSD": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Whether to enable UltraSSD." + } + }, + "gpuInstanceProfile": { + "type": "string", + "nullable": true, + "allowedValues": [ + "MIG1g", + "MIG2g", + "MIG3g", + "MIG4g", + "MIG7g" + ], + "metadata": { + "description": "Optional. GPUInstanceProfile to be used to specify GPU MIG instance profile for supported GPU VM SKU." + } + }, + "kubeletDiskType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the placement of emptyDir volumes, container runtime data root, and Kubelet ephemeral storage." + } + }, + "maxCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of nodes for auto-scaling." + } + }, + "maxPods": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The maximum number of pods that can run on a node." + } + }, + "minCount": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The minimum number of nodes for auto-scaling." + } + }, + "mode": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A cluster must have at least one \"System\" Agent Pool at all times. For additional information on agent pool restrictions and best practices, see: /azure/aks/use-system-pools." + } + }, + "nodeLabels": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. The node labels to be persisted across all nodes in agent pool." + } + }, + "nodePublicIpPrefixId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. ResourceId of the node PublicIPPrefix." + } + }, + "nodeTaints": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The taints added to new nodes during node pool create and scale. For example, key=value:NoSchedule." + } + }, + "orchestratorVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. As a best practice, you should upgrade all node pools in an AKS cluster to the same Kubernetes version. The node pool version must have the same major version as the control plane. The node pool minor version must be within two minor versions of the control plane version. The node pool version cannot be greater than the control plane version. For more information see upgrading a node pool (https://learn.microsoft.com/en-us/azure/aks/use-multiple-node-pools#upgrade-a-node-pool)." + } + }, + "osDiskSizeGB": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. OS Disk Size in GB to be used to specify the disk size for every machine in the master/agent pool. If you specify 0, it will apply the default osDisk size according to the vmSize specified." + } + }, + "osDiskType": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Ephemeral", + "Managed" + ], + "metadata": { + "description": "Optional. The default is \"Ephemeral\" if the VM supports it and has a cache disk larger than the requested OSDiskSizeGB. Otherwise, defaults to \"Managed\". May not be changed after creation. For more information see Ephemeral OS (https://learn.microsoft.com/en-us/azure/aks/cluster-configuration#ephemeral-os)." + } + }, + "osSku": { + "type": "string", + "nullable": true, + "allowedValues": [ + "AzureLinux", + "CBLMariner", + "Ubuntu", + "Windows2019", + "Windows2022" + ], + "metadata": { + "description": "Optional. Specifies the OS SKU used by the agent pool. The default is Ubuntu if OSType is Linux. The default is Windows2019 when Kubernetes <= 1.24 or Windows2022 when Kubernetes >= 1.25 if OSType is Windows." + } + }, + "osType": { + "type": "string", + "defaultValue": "Linux", + "allowedValues": [ + "Linux", + "Windows" + ], + "metadata": { + "description": "Optional. The operating system type. The default is Linux." + } + }, + "podSubnetId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Subnet ID for the pod IPs. If omitted, pod IPs are statically assigned on the node subnet (see vnetSubnetID for more details). This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}." + } + }, + "proximityPlacementGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The ID for the Proximity Placement Group." + } + }, + "scaleDownMode": { + "type": "string", + "defaultValue": "Delete", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "metadata": { + "description": "Optional. Describes how VMs are added to or removed from Agent Pools. See [billing states](https://learn.microsoft.com/en-us/azure/virtual-machines/states-billing)." + } + }, + "scaleSetEvictionPolicy": { + "type": "string", + "defaultValue": "Delete", + "allowedValues": [ + "Deallocate", + "Delete" + ], + "metadata": { + "description": "Optional. The eviction policy specifies what to do with the VM when it is evicted. The default is Delete. For more information about eviction see spot VMs." + } + }, + "scaleSetPriority": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Regular", + "Spot" + ], + "metadata": { + "description": "Optional. The Virtual Machine Scale Set priority." + } + }, + "spotMaxPrice": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Possible values are any decimal value greater than zero or -1 which indicates the willingness to pay any on-demand price. For more details on spot pricing, see spot VMs pricing (https://learn.microsoft.com/en-us/azure/virtual-machines/spot-vms#pricing)." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "type": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The type of Agent Pool." + } + }, + "maxSurge": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. This can either be set to an integer (e.g. \"5\") or a percentage (e.g. \"50%\"). If a percentage is specified, it is the percentage of the total agent pool size at the time of the upgrade. For percentages, fractional nodes are rounded up. If not specified, the default is 1. For more information, including best practices, see: /azure/aks/upgrade-cluster#customize-node-surge-upgrade." + } + }, + "vmSize": { + "type": "string", + "defaultValue": "Standard_D2s_v3", + "metadata": { + "description": "Optional. VM size. VM size availability varies by region. If a node contains insufficient compute resources (memory, cpu, etc) pods might fail to run correctly. For more details on restricted VM sizes, see: /azure/aks/quotas-skus-regions." + } + }, + "vnetSubnetId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Node Subnet ID. If this is not specified, a VNET and subnet will be generated and used. If no podSubnetID is specified, this applies to nodes and pods, otherwise it applies to just nodes. This is of the form: /subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Network/virtualNetworks/{virtualNetworkName}/subnets/{subnetName}." + } + }, + "workloadRuntime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Determines the type of workload a node can run." + } + } + }, + "resources": { + "managedCluster": { + "existing": true, + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2024-03-02-preview", + "name": "[parameters('managedClusterName')]" + }, + "agentPool": { + "type": "Microsoft.ContainerService/managedClusters/agentPools", + "apiVersion": "2023-07-02-preview", + "name": "[format('{0}/{1}', parameters('managedClusterName'), parameters('name'))]", + "properties": { + "availabilityZones": "[parameters('availabilityZones')]", + "count": "[parameters('count')]", + "creationData": "[if(not(empty(parameters('sourceResourceId'))), createObject('sourceResourceId', parameters('sourceResourceId')), null())]", + "enableAutoScaling": "[parameters('enableAutoScaling')]", + "enableEncryptionAtHost": "[parameters('enableEncryptionAtHost')]", + "enableFIPS": "[parameters('enableFIPS')]", + "enableNodePublicIP": "[parameters('enableNodePublicIP')]", + "enableUltraSSD": "[parameters('enableUltraSSD')]", + "gpuInstanceProfile": "[parameters('gpuInstanceProfile')]", + "kubeletDiskType": "[parameters('kubeletDiskType')]", + "maxCount": "[parameters('maxCount')]", + "maxPods": "[parameters('maxPods')]", + "minCount": "[parameters('minCount')]", + "mode": "[parameters('mode')]", + "nodeLabels": "[parameters('nodeLabels')]", + "nodePublicIPPrefixID": "[parameters('nodePublicIpPrefixId')]", + "nodeTaints": "[parameters('nodeTaints')]", + "orchestratorVersion": "[parameters('orchestratorVersion')]", + "osDiskSizeGB": "[parameters('osDiskSizeGB')]", + "osDiskType": "[parameters('osDiskType')]", + "osSKU": "[parameters('osSku')]", + "osType": "[parameters('osType')]", + "podSubnetID": "[parameters('podSubnetId')]", + "proximityPlacementGroupID": "[parameters('proximityPlacementGroupResourceId')]", + "scaleDownMode": "[parameters('scaleDownMode')]", + "scaleSetEvictionPolicy": "[parameters('scaleSetEvictionPolicy')]", + "scaleSetPriority": "[parameters('scaleSetPriority')]", + "spotMaxPrice": "[parameters('spotMaxPrice')]", + "tags": "[parameters('tags')]", + "type": "[parameters('type')]", + "upgradeSettings": { + "maxSurge": "[parameters('maxSurge')]" + }, + "vmSize": "[parameters('vmSize')]", + "vnetSubnetID": "[parameters('vnetSubnetId')]", + "workloadRuntime": "[parameters('workloadRuntime')]" + }, + "dependsOn": [ + "managedCluster" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the agent pool." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the agent pool." + }, + "value": "[resourceId('Microsoft.ContainerService/managedClusters/agentPools', parameters('managedClusterName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the agent pool was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "managedCluster" + ] + }, + "managedCluster_extension": { + "condition": "[not(empty(parameters('fluxExtension')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ManagedCluster-FluxExtension', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "clusterName": { + "value": "[parameters('name')]" + }, + "configurationProtectedSettings": { + "value": "[tryGet(parameters('fluxExtension'), 'configurationProtectedSettings')]" + }, + "configurationSettings": { + "value": "[tryGet(parameters('fluxExtension'), 'configurationSettings')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "extensionType": { + "value": "microsoft.flux" + }, + "fluxConfigurations": { + "value": "[tryGet(parameters('fluxExtension'), 'configurations')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "name": { + "value": "flux" + }, + "releaseNamespace": { + "value": "[coalesce(tryGet(parameters('fluxExtension'), 'releaseNamespace'), 'flux-system')]" + }, + "releaseTrain": { + "value": "[coalesce(tryGet(parameters('fluxExtension'), 'releaseTrain'), 'Stable')]" + }, + "version": { + "value": "[tryGet(parameters('fluxExtension'), 'version')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.23.1.45101", + "templateHash": "12293754418506359991" + }, + "name": "Kubernetes Configuration Extensions", + "description": "This module deploys a Kubernetes Configuration Extension.", + "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." + } + }, + "configurationProtectedSettings": { + "type": "secureObject", + "nullable": true, + "metadata": { + "description": "Optional. Configuration settings that are sensitive, as name-value pairs for configuring this extension." + } + }, + "configurationSettings": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Configuration settings, as name-value pairs for configuring this extension." + } + }, + "extensionType": { + "type": "string", + "metadata": { + "description": "Required. Type of the extension, of which this resource is an instance of. It must be one of the Extension Types registered with Microsoft.KubernetesConfiguration by the extension publisher." + } + }, + "releaseTrain": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. ReleaseTrain this extension participates in for auto-upgrade (e.g. Stable, Preview, etc.) - only if autoUpgradeMinorVersion is \"true\"." + } + }, + "releaseNamespace": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Namespace where the extension Release must be placed, for a Cluster scoped extension. If this namespace does not exist, it will be created." + } + }, + "targetNamespace": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Namespace where the extension will be created for an Namespace scoped extension. If this namespace does not exist, it will be created." + } + }, + "version": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Version of the extension for this extension, if it is \"pinned\" to a specific version." + } + }, + "fluxConfigurations": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. A list of flux configuraitons." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.kubernetesconfiguration-fluxconfig.{0}.{1}', replace('0.2.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" + } + } + } + } + }, + "managedCluster": { + "existing": true, + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2022-07-01", + "name": "[parameters('clusterName')]" + }, + "extension": { + "type": "Microsoft.KubernetesConfiguration/extensions", + "apiVersion": "2022-03-01", + "scope": "[format('Microsoft.ContainerService/managedClusters/{0}', parameters('clusterName'))]", + "name": "[parameters('name')]", + "properties": { + "autoUpgradeMinorVersion": "[if(not(empty(parameters('version'))), false(), true())]", + "configurationProtectedSettings": "[parameters('configurationProtectedSettings')]", + "configurationSettings": "[parameters('configurationSettings')]", + "extensionType": "[parameters('extensionType')]", + "releaseTrain": "[parameters('releaseTrain')]", + "scope": { + "cluster": "[if(not(empty(coalesce(parameters('releaseNamespace'), ''))), createObject('releaseNamespace', parameters('releaseNamespace')), null())]", + "namespace": "[if(not(empty(coalesce(parameters('targetNamespace'), ''))), createObject('targetNamespace', parameters('targetNamespace')), null())]" + }, + "version": "[parameters('version')]" + }, + "dependsOn": [ + "managedCluster" + ] + }, + "fluxConfiguration": { + "copy": { + "name": "fluxConfiguration", + "count": "[length(coalesce(parameters('fluxConfigurations'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-ManagedCluster-FluxConfiguration{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "clusterName": { + "value": "[parameters('clusterName')]" + }, + "scope": { + "value": "[coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()].scope]" + }, + "namespace": { + "value": "[coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()].namespace]" + }, + "sourceKind": "[if(contains(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'gitRepository'), createObject('value', 'GitRepository'), createObject('value', 'Bucket'))]", + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'name'), toLower(format('{0}-fluxconfiguration{1}', parameters('clusterName'), copyIndex())))]" + }, + "bucket": { + "value": "[tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'bucket')]" + }, + "configurationProtectedSettings": { + "value": "[tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'configurationProtectedSettings')]" + }, + "gitRepository": { + "value": "[tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'gitRepository')]" + }, + "kustomizations": { + "value": "[tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'kustomizations')]" + }, + "suspend": { + "value": "[tryGet(coalesce(parameters('fluxConfigurations'), createArray())[copyIndex()], 'suspend')]" + } + }, + "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": "13420454476526931427" + }, + "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", + "nullable": true, + "metadata": { + "description": "Optional. 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-extension.{0}.{1}', replace('0.2.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" + } + } + } + } + }, + "managedCluster": { + "existing": true, + "type": "Microsoft.ContainerService/managedClusters", + "apiVersion": "2022-07-01", + "name": "[parameters('clusterName')]" + }, + "fluxConfiguration": { + "type": "Microsoft.KubernetesConfiguration/fluxConfigurations", + "apiVersion": "2022-03-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": { + "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]" + } + } + } + }, + "dependsOn": [ + "extension", + "managedCluster" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the extension." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the extension." + }, + "value": "[extensionResourceId(resourceId('Microsoft.ContainerService/managedClusters', parameters('clusterName')), 'Microsoft.KubernetesConfiguration/extensions', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the extension was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "managedCluster" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the managed cluster." + }, + "value": "[resourceId('Microsoft.ContainerService/managedClusters', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the managed cluster was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the managed cluster." + }, + "value": "[parameters('name')]" + }, + "controlPlaneFQDN": { + "type": "string", + "metadata": { + "description": "The control plane FQDN of the managed cluster." + }, + "value": "[if(parameters('enablePrivateCluster'), reference('managedCluster').privateFQDN, reference('managedCluster').fqdn)]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('managedCluster', '2024-03-02-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "kubeletIdentityClientId": { + "type": "string", + "metadata": { + "description": "The Client ID of the AKS identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'clientId'), '')]" + }, + "kubeletIdentityObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of the AKS identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'objectId'), '')]" + }, + "kubeletIdentityResourceId": { + "type": "string", + "metadata": { + "description": "The Resource ID of the AKS identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(reference('managedCluster'), 'identityProfile'), 'kubeletidentity'), 'resourceId'), '')]" + }, + "omsagentIdentityObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of the OMS agent identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('managedCluster'), 'addonProfiles'), 'omsagent'), 'identity'), 'objectId'), '')]" + }, + "keyvaultIdentityObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of the Key Vault Secrets Provider identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('managedCluster'), 'addonProfiles'), 'azureKeyvaultSecretsProvider'), 'identity'), 'objectId'), '')]" + }, + "keyvaultIdentityClientId": { + "type": "string", + "metadata": { + "description": "The Client ID of the Key Vault Secrets Provider identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('managedCluster'), 'addonProfiles'), 'azureKeyvaultSecretsProvider'), 'identity'), 'clientId'), '')]" + }, + "ingressApplicationGatewayIdentityObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of Application Gateway Ingress Controller (AGIC) identity." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('managedCluster'), 'addonProfiles'), 'ingressApplicationGateway'), 'identity'), 'objectId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('managedCluster', '2024-03-02-preview', 'full').location]" + }, + "oidcIssuerUrl": { + "type": "string", + "metadata": { + "description": "The OIDC token issuer URL." + }, + "value": "[coalesce(tryGet(tryGet(reference('managedCluster'), 'oidcIssuerProfile'), 'issuerURL'), '')]" + }, + "addonProfiles": { + "type": "object", + "metadata": { + "description": "The addonProfiles of the Kubernetes cluster." + }, + "value": "[coalesce(tryGet(reference('managedCluster'), 'addonProfiles'), createObject())]" + }, + "webAppRoutingIdentityObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of Web Application Routing." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('managedCluster'), 'ingressProfile'), 'webAppRouting'), 'identity'), 'objectId'), '')]" + } + } + } + }, + "dependsOn": [ + "logAnalytics" + ] + }, + "containerRegistry": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-container-registry', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('containerRegistryName')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "publicNetworkAccess": { + "value": "[parameters('publicNetworkAccess')]" + }, + "scopeMaps": { + "value": "[parameters('scopeMaps')]" + }, + "acrSku": { + "value": "[parameters('acrSku')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "diagnosticSettings": { + "value": [ + { + "logCategoriesAndGroups": [ + { + "category": "ContainerRegistryRepositoryEvents", + "enabled": true + }, + { + "category": "ContainerRegistryLoginEvents", + "enabled": true + } + ], + "workspaceResourceId": "[if(not(empty(parameters('logAnalyticsName'))), resourceId('Microsoft.OperationalInsights/workspaces', parameters('logAnalyticsName')), '')]", + "metricCategories": [ + { + "category": "AllMetrics", + "enabled": true + } + ] + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "[parameters('containerRegistryRoleName')]", + "principalId": "[reference('managedCluster').outputs.kubeletIdentityObjectId.value]", + "roleDefinitionIdOrName": "[variables('acrPullRole')]" + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "8799580877381308457" + }, + "name": "Azure Container Registries (ACR)", + "description": "This module deploys an Azure Container Registry (ACR).", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, using 'latest'." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "nullable": true + }, + "scopeMapsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Required. Name of your Azure Container Registry." + } + }, + "acrAdminUserEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable admin user that have push / pull permission to the registry." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "acrSku": { + "type": "string", + "defaultValue": "Basic", + "allowedValues": [ + "Basic", + "Premium", + "Standard" + ], + "metadata": { + "description": "Optional. Tier of your Azure container registry." + } + }, + "exportPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the export policy is enabled or not." + } + }, + "quarantinePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the quarantine policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "trustPolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the trust policy is enabled or not. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "retentionPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the retention policy is enabled or not." + } + }, + "retentionPolicyDays": { + "type": "int", + "defaultValue": 15, + "metadata": { + "description": "Optional. The number of days to retain an untagged manifest after which it gets purged." + } + }, + "azureADAuthenticationAsArmPolicyStatus": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The value that indicates whether the policy for using ARM audience token for a container registr is enabled or not. Default is enabled." + } + }, + "softDeletePolicyStatus": { + "type": "string", + "defaultValue": "disabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. Soft Delete policy status. Default is disabled." + } + }, + "softDeletePolicyDays": { + "type": "int", + "defaultValue": 7, + "metadata": { + "description": "Optional. The number of days after which a soft-deleted item is permanently deleted." + } + }, + "dataEndpointEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable a single data endpoint per region for serving data. Not relevant in case of disabled public access. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "publicNetworkAccess": { + "type": "string", + "nullable": true, + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkRuleSetIpRules are not set. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "networkRuleBypassOptions": { + "type": "string", + "defaultValue": "AzureServices", + "allowedValues": [ + "AzureServices", + "None" + ], + "metadata": { + "description": "Optional. Whether to allow trusted Azure services to access a network restricted registry." + } + }, + "networkRuleSetDefaultAction": { + "type": "string", + "defaultValue": "Deny", + "allowedValues": [ + "Allow", + "Deny" + ], + "metadata": { + "description": "Optional. The default action of allow or deny when no other rules match." + } + }, + "networkRuleSetIpRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The IP ACL rules. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible. Note, requires the 'acrSku' to be 'Premium'." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + }, + "replications": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All replications to create." + } + }, + "webhooks": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. All webhooks to create." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "anonymousPullEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enables registry-wide pull from unauthenticated clients. It's in preview and available in the Standard and Premium service tiers." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "metadata": { + "description": "Optional. The customer managed key definition." + } + }, + "cacheRules": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Array of Cache Rules." + } + }, + "credentialSets": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Array of Credential Sets." + } + }, + "scopeMaps": { + "$ref": "#/definitions/scopeMapsType", + "metadata": { + "description": "Optional. Scope maps setting." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned, UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "AcrDelete": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c2f4ef07-c644-48eb-af81-4b1b4947fb11')]", + "AcrImageSigner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '6cef56e8-d556-48e5-a04f-b8e64114680f')]", + "AcrPull": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]", + "AcrPush": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8311e382-0749-4cb8-b61a-304f252e45ec')]", + "AcrQuarantineReader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'cdda3590-29a3-44f6-95f2-9f980659eb04')]", + "AcrQuarantineWriter": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c8d4ff99-41c3-41a8-9f60-21dfdad59608')]", + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/')), coalesce(tryGet(parameters('customerManagedKey'), 'keyName'), 'dummyKey'))]", + "dependsOn": [ + "cMKKeyVault" + ] + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.containerregistry-registry.{0}.{1}', replace('0.4.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), 'dummyVault'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '//'), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '////'), '/')[4]]", + "name": "[last(split(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), 'dummyMsi'), '/'))]" + }, + "registry": { + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "tags": "[parameters('tags')]", + "sku": { + "name": "[parameters('acrSku')]" + }, + "properties": { + "anonymousPullEnabled": "[parameters('anonymousPullEnabled')]", + "adminUserEnabled": "[parameters('acrAdminUserEnabled')]", + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('status', 'enabled', 'keyVaultProperties', createObject('identity', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), ''))), reference('cMKUserAssignedIdentity').clientId, null()), 'keyIdentifier', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, parameters('customerManagedKey').keyVersion), reference('cMKKeyVault::cMKKey').keyUriWithVersion))), null())]", + "policies": { + "azureADAuthenticationAsArmPolicy": { + "status": "[parameters('azureADAuthenticationAsArmPolicyStatus')]" + }, + "exportPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('exportPolicyStatus')), null())]", + "quarantinePolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('status', parameters('quarantinePolicyStatus')), null())]", + "trustPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('type', 'Notary', 'status', parameters('trustPolicyStatus')), null())]", + "retentionPolicy": "[if(equals(parameters('acrSku'), 'Premium'), createObject('days', parameters('retentionPolicyDays'), 'status', parameters('retentionPolicyStatus')), null())]", + "softDeletePolicy": { + "retentionDays": "[parameters('softDeletePolicyDays')]", + "status": "[parameters('softDeletePolicyStatus')]" + } + }, + "dataEndpointEnabled": "[parameters('dataEndpointEnabled')]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(parameters('privateEndpoints'))), empty(parameters('networkRuleSetIpRules'))), 'Disabled', null()))]", + "networkRuleBypassOptions": "[parameters('networkRuleBypassOptions')]", + "networkRuleSet": "[if(not(empty(parameters('networkRuleSetIpRules'))), createObject('defaultAction', parameters('networkRuleSetDefaultAction'), 'ipRules', parameters('networkRuleSetIpRules')), null())]", + "zoneRedundancy": "[if(equals(parameters('acrSku'), 'Premium'), parameters('zoneRedundancy'), null())]" + }, + "dependsOn": [ + "cMKKeyVault", + "cMKUserAssignedIdentity" + ] + }, + "registry_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.ContainerRegistry/registries/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_diagnosticSettings": { + "copy": { + "name": "registry_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.ContainerRegistry/registries/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_roleAssignments": { + "copy": { + "name": "registry_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.ContainerRegistry/registries/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "registry" + ] + }, + "registry_scopeMaps": { + "copy": { + "name": "registry_scopeMaps", + "count": "[length(coalesce(parameters('scopeMaps'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Scope-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'name')]" + }, + "actions": { + "value": "[coalesce(parameters('scopeMaps'), createArray())[copyIndex()].actions]" + }, + "description": { + "value": "[tryGet(coalesce(parameters('scopeMaps'), createArray())[copyIndex()], 'description')]" + }, + "registryName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "9144531012597082524" + }, + "name": "Container Registries scopeMaps", + "description": "This module deploys an Azure Container Registry (ACR) scopeMap.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}-scopemaps', parameters('registryName'))]", + "metadata": { + "description": "Optional. The name of the scope map." + } + }, + "actions": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. The list of scoped permissions for registry artifacts." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The user friendly description of the scope map." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "scopeMap": { + "type": "Microsoft.ContainerRegistry/registries/scopeMaps", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "actions": "[parameters('actions')]", + "description": "[parameters('description')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the scope map." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the scope map was created in." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the scope map." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/scopeMaps', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_replications": { + "copy": { + "name": "registry_replications", + "count": "[length(coalesce(parameters('replications'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Replication-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(parameters('replications'), createArray())[copyIndex()].location]" + }, + "regionEndpointEnabled": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'regionEndpointEnabled')]" + }, + "zoneRedundancy": { + "value": "[tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'zoneRedundancy')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('replications'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "8531695368487734118" + }, + "name": "Azure Container Registry (ACR) Replications", + "description": "This module deploys an Azure Container Registry (ACR) Replication.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the replication." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "regionEndpointEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies whether the replication regional endpoint is enabled. Requests will not be routed to a replication whose regional endpoint is disabled, however its data will continue to be synced with other replications." + } + }, + "zoneRedundancy": { + "type": "string", + "defaultValue": "Disabled", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "metadata": { + "description": "Optional. Whether or not zone redundancy is enabled for this container registry." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "replication": { + "type": "Microsoft.ContainerRegistry/registries/replications", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "regionEndpointEnabled": "[parameters('regionEndpointEnabled')]", + "zoneRedundancy": "[parameters('zoneRedundancy')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the replication." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the replication." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/replications', parameters('registryName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the replication was created in." + }, + "value": "[resourceGroup().name]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('replication', '2023-06-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_credentialSets": { + "copy": { + "name": "registry_credentialSets", + "count": "[length(coalesce(parameters('credentialSets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-CredentialSet-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "managedIdentities": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].managedIdentities]" + }, + "authCredentials": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].authCredentials]" + }, + "loginServer": { + "value": "[coalesce(parameters('credentialSets'), createArray())[copyIndex()].loginServer]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "12196074162662855376" + }, + "name": "Container Registries Credential Sets", + "description": "This module deploys an ACR Credential Set.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + } + } + }, + "authCredentialsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential." + } + }, + "usernameSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the username." + } + }, + "passwordSecretIdentifier": { + "type": "string", + "metadata": { + "description": "Required. KeyVault Secret URI for accessing the password." + } + } + } + } + } + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the credential set." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Required. The managed identity definition for this resource." + } + }, + "authCredentials": { + "$ref": "#/definitions/authCredentialsType", + "metadata": { + "description": "Required. List of authentication credentials stored for an upstream. Usually consists of a primary and an optional secondary credential." + } + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "Required. The credentials are stored for this upstream or login server." + } + } + }, + "variables": { + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), 'SystemAssigned', null())), null())]" + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "credentialSet": { + "type": "Microsoft.ContainerRegistry/registries/credentialSets", + "apiVersion": "2023-11-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "identity": "[variables('identity')]", + "properties": { + "authCredentials": "[parameters('authCredentials')]", + "loginServer": "[parameters('loginServer')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Credential Set." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Credential Set." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Credential Set." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/credentialSets', parameters('registryName'), parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('credentialSet', '2023-11-01-preview', 'full'), 'identity'), 'principalId'), '')]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_cacheRules": { + "copy": { + "name": "registry_cacheRules", + "count": "[length(coalesce(parameters('cacheRules'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Cache-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "registryName": { + "value": "[parameters('name')]" + }, + "sourceRepository": { + "value": "[coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository]" + }, + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'name'), replace(replace(coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository, '/', '-'), '.', '-'))]" + }, + "targetRepository": { + "value": "[coalesce(tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'targetRepository'), coalesce(parameters('cacheRules'), createArray())[copyIndex()].sourceRepository)]" + }, + "credentialSetResourceId": { + "value": "[tryGet(coalesce(parameters('cacheRules'), createArray())[copyIndex()], 'credentialSetResourceId')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "4294329625336671928" + }, + "name": "Container Registries Cache", + "description": "Cache for Azure Container Registry (Preview) feature allows users to cache container images in a private container registry. Cache for ACR, is a preview feature available in Basic, Standard, and Premium service tiers ([ref](https://learn.microsoft.com/en-us/azure/container-registry/tutorial-registry-cache)).", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[replace(replace(parameters('sourceRepository'), '/', '-'), '.', '-')]", + "metadata": { + "description": "Optional. The name of the cache rule. Will be dereived from the source repository name if not defined." + } + }, + "sourceRepository": { + "type": "string", + "metadata": { + "description": "Required. Source repository pulled from upstream." + } + }, + "targetRepository": { + "type": "string", + "defaultValue": "[parameters('sourceRepository')]", + "metadata": { + "description": "Optional. Target repository specified in docker pull command. E.g.: docker pull myregistry.azurecr.io/{targetRepository}:{tag}." + } + }, + "credentialSetResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of the credential store which is associated with the cache rule." + } + } + }, + "resources": [ + { + "type": "Microsoft.ContainerRegistry/registries/cacheRules", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "properties": { + "sourceRepository": "[parameters('sourceRepository')]", + "targetRepository": "[parameters('targetRepository')]", + "credentialSetResourceId": "[parameters('credentialSetResourceId')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Cache Rule." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Cache Rule." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Cache Rule." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/cacheRules', parameters('registryName'), parameters('name'))]" + } + } + } + }, + "dependsOn": [ + "registry", + "registry_credentialSets" + ] + }, + "registry_webhooks": { + "copy": { + "name": "registry_webhooks", + "count": "[length(coalesce(parameters('webhooks'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-Registry-Webhook-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].name]" + }, + "registryName": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'location'), parameters('location'))]" + }, + "action": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'action'), createArray('chart_delete', 'chart_push', 'delete', 'push', 'quarantine'))]" + }, + "customHeaders": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'customHeaders')]" + }, + "scope": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'scope')]" + }, + "status": { + "value": "[tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'status')]" + }, + "serviceUri": { + "value": "[coalesce(parameters('webhooks'), createArray())[copyIndex()].serviceUri]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('webhooks'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "14912363209364245195" + }, + "name": "Azure Container Registry (ACR) Webhooks", + "description": "This module deploys an Azure Container Registry (ACR) Webhook.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "registryName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent registry. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "[format('{0}webhook', parameters('registryName'))]", + "minLength": 5, + "maxLength": 50, + "metadata": { + "description": "Optional. The name of the registry webhook." + } + }, + "serviceUri": { + "type": "string", + "metadata": { + "description": "Required. The service URI for the webhook to post notifications." + } + }, + "status": { + "type": "string", + "defaultValue": "enabled", + "allowedValues": [ + "disabled", + "enabled" + ], + "metadata": { + "description": "Optional. The status of the webhook at the time the operation was called." + } + }, + "action": { + "type": "array", + "defaultValue": [ + "chart_delete", + "chart_push", + "delete", + "push", + "quarantine" + ], + "metadata": { + "description": "Optional. The list of actions that trigger the webhook to post notifications." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "customHeaders": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Custom headers that will be added to the webhook notifications." + } + }, + "scope": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The scope of repositories where the event can be triggered. For example, 'foo:*' means events for all tags under repository 'foo'. 'foo:bar' means events for 'foo:bar' only. 'foo' is equivalent to 'foo:latest'. Empty means all events." + } + } + }, + "resources": { + "registry": { + "existing": true, + "type": "Microsoft.ContainerRegistry/registries", + "apiVersion": "2023-06-01-preview", + "name": "[parameters('registryName')]" + }, + "webhook": { + "type": "Microsoft.ContainerRegistry/registries/webhooks", + "apiVersion": "2023-06-01-preview", + "name": "[format('{0}/{1}', parameters('registryName'), parameters('name'))]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "actions": "[parameters('action')]", + "customHeaders": "[parameters('customHeaders')]", + "scope": "[parameters('scope')]", + "serviceUri": "[parameters('serviceUri')]", + "status": "[parameters('status')]" + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the webhook." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries/webhooks', parameters('registryName'), parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the webhook." + }, + "value": "[parameters('name')]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "actions": { + "type": "array", + "metadata": { + "description": "The actions of the webhook." + }, + "value": "[reference('webhook').actions]" + }, + "status": { + "type": "string", + "metadata": { + "description": "The status of the webhook." + }, + "value": "[reference('webhook').status]" + }, + "provistioningState": { + "type": "string", + "metadata": { + "description": "The provisioning state of the webhook." + }, + "value": "[reference('webhook').provisioningState]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('webhook', '2023-06-01-preview', 'full').location]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + }, + "registry_privateEndpoints": { + "copy": { + "name": "registry_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'registry')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "registry" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The Name of the Azure container registry." + }, + "value": "[parameters('name')]" + }, + "loginServer": { + "type": "string", + "metadata": { + "description": "The reference to the Azure container registry." + }, + "value": "[reference(resourceId('Microsoft.ContainerRegistry/registries', parameters('name')), '2019-05-01').loginServer]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the Azure container registry." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Azure container registry." + }, + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('name'))]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('registry', '2023-06-01-preview', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('registry', '2023-06-01-preview', 'full').location]" + }, + "credentialSetsSystemAssignedMIPrincipalIds": { + "type": "array", + "metadata": { + "description": "The Principal IDs of the ACR Credential Sets system-assigned identities." + }, + "copy": { + "count": "[length(range(0, length(parameters('credentialSets'))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(parameters('credentialSets')))[copyIndex()])).outputs.systemAssignedMIPrincipalId.value]" + } + }, + "credentialSetsResourceIds": { + "type": "array", + "metadata": { + "description": "The Resource IDs of the ACR Credential Sets." + }, + "copy": { + "count": "[length(range(0, length(parameters('credentialSets'))))]", + "input": "[reference(format('registry_credentialSets[{0}]', range(0, length(parameters('credentialSets')))[copyIndex()])).outputs.resourceId.value]" + } + } + } + } + }, + "dependsOn": [ + "logAnalytics", + "managedCluster" + ] + }, + "keyVault": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-key-vault', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('keyVaultName')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + }, + "accessPolicies": { + "value": [ + { + "objectId": "[reference('managedCluster').outputs.kubeletIdentityObjectId.value]", + "permissions": { + "secrets": [ + "get", + "list" + ] + } + } + ] + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "6878673228466609441" + }, + "name": "Key Vaults", + "description": "This module deploys a Key Vault.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "diagnosticSettingType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of metrics that will be streamed. \"allMetrics\" includes all possible metrics for the resource. Set to `[]` to disable metric collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "privateEndpointType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private endpoint." + } + }, + "location": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The location to deploy the private endpoint to." + } + }, + "privateLinkServiceConnectionName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private link connection to create." + } + }, + "service": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The subresource to deploy the private endpoint for. For example \"vault\", \"mysqlServer\" or \"dataFactory\"." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + } + }, + "isManualConnection": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. If Manual Private Link Connection is required." + } + }, + "manualConnectionRequestMessage": { + "type": "string", + "nullable": true, + "maxLength": 140, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with the manual connection request." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "enableTelemetry": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + }, + "resourceGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify if you want to deploy the Private Endpoint into a different resource group than the main resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + } + }, + "nullable": true + }, + "secretsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the secret is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the secret will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the secret becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the secret." + } + }, + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + } + }, + "nullable": true + }, + "keysType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributes": { + "type": "object", + "properties": { + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Defines whether the key is enabled or disabled." + } + }, + "exp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Defines when the key will become invalid. Defined in seconds since 1970-01-01T00:00:00Z." + } + }, + "nbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. If set, defines the date from which onwards the key becomes valid. Defined in seconds since 1970-01-01T00:00:00Z." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Contains attributes of the key." + } + }, + "curveName": { + "type": "string", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "nullable": true, + "metadata": { + "description": "Optional. The elliptic curve name. Only works if \"keySize\" equals \"EC\" or \"EC-HSM\". Default is \"P-256\"." + } + }, + "keyOps": { + "type": "array", + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "release", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. The allowed operations on this key." + } + }, + "keySize": { + "type": "int", + "allowedValues": [ + 2048, + 3072, + 4096 + ], + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. Only works if \"keySize\" equals \"RSA\" or \"RSA-HSM\". Default is \"4096\"." + } + }, + "kty": { + "type": "string", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of the key. Default is \"EC\"." + } + }, + "releasePolicy": { + "type": "object", + "properties": { + "contentType": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Content type and version of key release policy." + } + }, + "data": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Blob encoding the policy rules under which the key can be released." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "rotationPolicy": { + "$ref": "#/definitions/rotationPoliciesType", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + } + }, + "nullable": true + }, + "rotationPoliciesType": { + "type": "object", + "properties": { + "attributes": { + "type": "object", + "properties": { + "expiryTime": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The expiration time for the new key version. It should be in ISO8601 format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The attributes of key rotation policy." + } + }, + "lifetimeActions": { + "type": "array", + "items": { + "type": "object", + "properties": { + "action": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "Notify", + "Rotate" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of action." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The action of key rotation policy lifetimeAction." + } + }, + "trigger": { + "type": "object", + "properties": { + "timeAfterCreate": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration after key creation to rotate the key. It only applies to rotate. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + }, + "timeBeforeExpiry": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The time duration before key expiring to rotate or notify. It will be in ISO 8601 duration format. Eg: \"P90D\", \"P1Y\"." + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The trigger of key rotation policy lifetimeAction." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The lifetimeActions for key rotation action." + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "maxLength": 24, + "metadata": { + "description": "Required. Name of the Key Vault. Must be globally unique." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. All access policies to create." + } + }, + "secrets": { + "$ref": "#/definitions/secretsType", + "nullable": true, + "metadata": { + "description": "Optional. All secrets to create." + } + }, + "keys": { + "$ref": "#/definitions/keysType", + "nullable": true, + "metadata": { + "description": "Optional. All keys to create." + } + }, + "enableVaultForDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for deployment by script or compute." + } + }, + "enableVaultForTemplateDeployment": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the vault is enabled for a template deployment." + } + }, + "enableVaultForDiskEncryption": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the azure platform has access to the vault for enabling disk encryption scenarios." + } + }, + "enableSoftDelete": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Switch to enable/disable Key Vault's soft delete feature." + } + }, + "softDeleteRetentionInDays": { + "type": "int", + "defaultValue": 90, + "metadata": { + "description": "Optional. softDelete data retention days. It accepts >=7 and <=90." + } + }, + "enableRbacAuthorization": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Property that controls how data actions are authorized. When true, the key vault will use Role Based Access Control (RBAC) for authorization of data actions, and the access policies specified in vault properties will be ignored. When false, the key vault will use the access policies specified in vault properties, and any policy stored on Azure Resource Manager will be ignored. Note that management actions are always authorized with RBAC." + } + }, + "createMode": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The vault's create mode to indicate whether the vault need to be recovered or not. - recover or default." + } + }, + "enablePurgeProtection": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Provide 'true' to enable Key Vault's purge protection feature." + } + }, + "sku": { + "type": "string", + "defaultValue": "premium", + "allowedValues": [ + "premium", + "standard" + ], + "metadata": { + "description": "Optional. Specifies the SKU for the vault." + } + }, + "networkAcls": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Rules governing the accessibility of the resource from specific network locations." + } + }, + "publicNetworkAccess": { + "type": "string", + "defaultValue": "", + "allowedValues": [ + "", + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Whether or not public network access is allowed for this resource. For security reasons it should be disabled. If not specified, it will be disabled by default if private endpoints are set and networkAcls are not set." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "privateEndpoints": { + "$ref": "#/definitions/privateEndpointType", + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "diagnosticSettings": { + "$ref": "#/definitions/diagnosticSettingType", + "metadata": { + "description": "Optional. The diagnostic settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + }, + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Certificates Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'a4417e6f-fecd-4de8-b567-7b0420556985')]", + "Key Vault Certificate User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'db79e9a7-68ee-4b58-9aeb-b90e7c24fcba')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.keyvault-vault.{0}.{1}', replace('0.7.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "keyVault": { + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "enabledForDeployment": "[parameters('enableVaultForDeployment')]", + "enabledForTemplateDeployment": "[parameters('enableVaultForTemplateDeployment')]", + "enabledForDiskEncryption": "[parameters('enableVaultForDiskEncryption')]", + "enableSoftDelete": "[parameters('enableSoftDelete')]", + "softDeleteRetentionInDays": "[parameters('softDeleteRetentionInDays')]", + "enableRbacAuthorization": "[parameters('enableRbacAuthorization')]", + "createMode": "[parameters('createMode')]", + "enablePurgeProtection": "[if(parameters('enablePurgeProtection'), parameters('enablePurgeProtection'), null())]", + "tenantId": "[subscription().tenantId]", + "accessPolicies": "[variables('formattedAccessPolicies')]", + "sku": { + "name": "[parameters('sku')]", + "family": "A" + }, + "networkAcls": "[if(not(empty(coalesce(parameters('networkAcls'), createObject()))), createObject('bypass', tryGet(parameters('networkAcls'), 'bypass'), 'defaultAction', tryGet(parameters('networkAcls'), 'defaultAction'), 'virtualNetworkRules', coalesce(tryGet(parameters('networkAcls'), 'virtualNetworkRules'), createArray()), 'ipRules', coalesce(tryGet(parameters('networkAcls'), 'ipRules'), createArray())), null())]", + "publicNetworkAccess": "[if(not(empty(parameters('publicNetworkAccess'))), parameters('publicNetworkAccess'), if(and(not(empty(coalesce(parameters('privateEndpoints'), createArray()))), empty(coalesce(parameters('networkAcls'), createObject()))), 'Disabled', null()))]" + } + }, + "keyVault_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_diagnosticSettings": { + "copy": { + "name": "keyVault_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + }, + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_roleAssignments": { + "copy": { + "name": "keyVault_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_accessPolicies": { + "condition": "[not(empty(parameters('accessPolicies')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-AccessPolicies', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[parameters('name')]" + }, + "accessPolicies": { + "value": "[parameters('accessPolicies')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "7494731697751039419" + }, + "name": "Key Vault Access Policies", + "description": "This module deploys a Key Vault Access Policy.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "accessPoliciesType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "tenantId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The tenant ID that is used for authenticating requests to the key vault." + } + }, + "objectId": { + "type": "string", + "metadata": { + "description": "Required. The object ID of a user, service principal or security group in the tenant for the vault." + } + }, + "applicationId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Application ID of the client making request on behalf of a principal." + } + }, + "permissions": { + "type": "object", + "properties": { + "keys": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "decrypt", + "delete", + "encrypt", + "get", + "getrotationpolicy", + "import", + "list", + "purge", + "recover", + "release", + "restore", + "rotate", + "setrotationpolicy", + "sign", + "unwrapKey", + "update", + "verify", + "wrapKey" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to keys." + } + }, + "secrets": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "get", + "list", + "purge", + "recover", + "restore", + "set" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to secrets." + } + }, + "certificates": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "create", + "delete", + "deleteissuers", + "get", + "getissuers", + "import", + "list", + "listissuers", + "managecontacts", + "manageissuers", + "purge", + "recover", + "restore", + "setissuers", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to certificates." + } + }, + "storage": { + "type": "array", + "allowedValues": [ + "all", + "backup", + "delete", + "deletesas", + "get", + "getsas", + "list", + "listsas", + "purge", + "recover", + "regeneratekey", + "restore", + "set", + "setsas", + "update" + ], + "nullable": true, + "metadata": { + "description": "Optional. Permissions to storage accounts." + } + } + }, + "metadata": { + "description": "Required. Permissions the identity has for keys, secrets and certificates." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "accessPolicies": { + "$ref": "#/definitions/accessPoliciesType", + "metadata": { + "description": "Optional. An array of 0 to 16 identities that have access to the key vault. All identities in the array must use the same tenant ID as the key vault's tenant ID." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedAccessPolicies", + "count": "[length(coalesce(parameters('accessPolicies'), createArray()))]", + "input": { + "applicationId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'applicationId'), '')]", + "objectId": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].objectId]", + "permissions": "[coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')].permissions]", + "tenantId": "[coalesce(tryGet(coalesce(parameters('accessPolicies'), createArray())[copyIndex('formattedAccessPolicies')], 'tenantId'), tenant().tenantId)]" + } + } + ] + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "policies": { + "type": "Microsoft.KeyVault/vaults/accessPolicies", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), 'add')]", + "properties": { + "accessPolicies": "[variables('formattedAccessPolicies')]" + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the access policies assignment was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policies assignment." + }, + "value": "add" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policies assignment." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/accessPolicies', parameters('keyVaultName'), 'add')]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_secrets": { + "copy": { + "name": "keyVault_secrets", + "count": "[length(coalesce(parameters('secrets'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Secret-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].name]" + }, + "value": { + "value": "[coalesce(parameters('secrets'), createArray())[copyIndex()].value]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'enabled')]" + }, + "attributesExp": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'exp')]" + }, + "attributesNbf": { + "value": "[tryGet(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'attributes'), 'nbf')]" + }, + "contentType": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'contentType')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('secrets'), createArray())[copyIndex()], 'roleAssignments')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "4990258423482296566" + }, + "name": "Key Vault Secrets", + "description": "This module deploys a Key Vault Secret.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the secret." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "contentType": { + "type": "securestring", + "nullable": true, + "metadata": { + "description": "Optional. The content type of the secret." + } + }, + "value": { + "type": "securestring", + "metadata": { + "description": "Required. The value of the secret. NOTE: \"value\" will never be returned from the service, as APIs using this model are is intended for internal use in ARM deployments. Users should use the data-plane REST service for interaction with vault secrets." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Key Vault Secrets Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b86a8fe4-44ce-4948-aee5-eccb2c155cd7')]", + "Key Vault Secrets User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4633458b-17de-408a-b874-0445c86b69e6')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "secret": { + "type": "Microsoft.KeyVault/vaults/secrets", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "contentType": "[parameters('contentType')]", + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "value": "[parameters('value')]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "secret_roleAssignments": { + "copy": { + "name": "secret_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/secrets/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "secret" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the secret." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the secret." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the secret was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_keys": { + "copy": { + "name": "keyVault_keys", + "count": "[length(coalesce(parameters('keys'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-KeyVault-Key-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('keys'), createArray())[copyIndex()].name]" + }, + "keyVaultName": { + "value": "[parameters('name')]" + }, + "attributesEnabled": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'enabled')]" + }, + "attributesExp": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'exp')]" + }, + "attributesNbf": { + "value": "[tryGet(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'attributes'), 'nbf')]" + }, + "curveName": "[if(and(not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA')), not(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM'))), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'curveName'), 'P-256')), createObject('value', null()))]", + "keyOps": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keyOps')]" + }, + "keySize": "[if(or(equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA'), equals(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'RSA-HSM')), createObject('value', coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'keySize'), 4096)), createObject('value', null()))]", + "releasePolicy": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'releasePolicy'), createObject())]" + }, + "kty": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'kty'), 'EC')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "rotationPolicy": { + "value": "[tryGet(coalesce(parameters('keys'), createArray())[copyIndex()], 'rotationPolicy')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "10436564794447478489" + }, + "name": "Key Vault Keys", + "description": "This module deploys a Key Vault Key.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "keyVaultName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent key vault. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the key." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Resource tags." + } + }, + "attributesEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Determines whether the object is enabled." + } + }, + "attributesExp": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Expiry date in seconds since 1970-01-01T00:00:00Z. For security reasons, it is recommended to set an expiration date whenever possible." + } + }, + "attributesNbf": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Not before date in seconds since 1970-01-01T00:00:00Z." + } + }, + "curveName": { + "type": "string", + "defaultValue": "P-256", + "allowedValues": [ + "P-256", + "P-256K", + "P-384", + "P-521" + ], + "metadata": { + "description": "Optional. The elliptic curve name." + } + }, + "keyOps": { + "type": "array", + "nullable": true, + "allowedValues": [ + "decrypt", + "encrypt", + "import", + "sign", + "unwrapKey", + "verify", + "wrapKey" + ], + "metadata": { + "description": "Optional. Array of JsonWebKeyOperation." + } + }, + "keySize": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. The key size in bits. For example: 2048, 3072, or 4096 for RSA." + } + }, + "kty": { + "type": "string", + "defaultValue": "EC", + "allowedValues": [ + "EC", + "EC-HSM", + "RSA", + "RSA-HSM" + ], + "metadata": { + "description": "Optional. The type of the key." + } + }, + "releasePolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key release policy." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "rotationPolicy": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Key rotation policy properties object." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Key Vault Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '00482a5a-887f-4fb3-b363-3b7fe8e74483')]", + "Key Vault Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f25e0fa2-a7c8-4377-a976-54943a77a395')]", + "Key Vault Crypto Officer": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '14b46e9e-c2b7-41b4-b07b-48a6ebf60603')]", + "Key Vault Crypto Service Encryption User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e147488a-f6f5-4113-8e2d-b22465e65bf6')]", + "Key Vault Crypto User": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '12338af0-0e69-4776-bea7-57ae8d297424')]", + "Key Vault Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '21090545-7ca7-4776-b22c-e363652d74d2')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "keyVault": { + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2022-07-01", + "name": "[parameters('keyVaultName')]" + }, + "key": { + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2022-07-01", + "name": "[format('{0}/{1}', parameters('keyVaultName'), parameters('name'))]", + "tags": "[parameters('tags')]", + "properties": { + "attributes": { + "enabled": "[parameters('attributesEnabled')]", + "exp": "[parameters('attributesExp')]", + "nbf": "[parameters('attributesNbf')]" + }, + "curveName": "[parameters('curveName')]", + "keyOps": "[parameters('keyOps')]", + "keySize": "[parameters('keySize')]", + "kty": "[parameters('kty')]", + "rotationPolicy": "[coalesce(parameters('rotationPolicy'), createObject())]", + "release_policy": "[coalesce(parameters('releasePolicy'), createObject())]" + }, + "dependsOn": [ + "keyVault" + ] + }, + "key_roleAssignments": { + "copy": { + "name": "key_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.KeyVault/vaults/{0}/keys/{1}', parameters('keyVaultName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "key" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the key." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults/keys', parameters('keyVaultName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key was created in." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + }, + "keyVault_privateEndpoints": { + "copy": { + "name": "keyVault_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-keyVault-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "resourceGroup": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupName'), '')]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'name'), format('pep-{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex()))]" + }, + "privateLinkServiceConnections": "[if(not(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true())), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')))))), createObject('value', null()))]", + "manualPrivateLinkServiceConnections": "[if(equals(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'isManualConnection'), true()), createObject('value', createArray(createObject('name', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateLinkServiceConnectionName'), format('{0}-{1}-{2}', last(split(resourceId('Microsoft.KeyVault/vaults', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.KeyVault/vaults', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'vault')), 'requestMessage', coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'manualConnectionRequestMessage'), 'Manual approval required.'))))), createObject('value', null()))]", + "subnetResourceId": { + "value": "[coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId]" + }, + "enableTelemetry": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'enableTelemetry'), parameters('enableTelemetry'))]" + }, + "location": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'location'), reference(split(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()].subnetResourceId, '/subnets/')[0], '2020-06-01', 'Full').location)]" + }, + "lock": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'lock'), parameters('lock'))]" + }, + "privateDnsZoneGroupName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroupName')]" + }, + "privateDnsZoneResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneResourceIds')]" + }, + "roleAssignments": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" + }, + "tags": { + "value": "[coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'tags'), parameters('tags'))]" + }, + "customDnsConfigs": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customDnsConfigs')]" + }, + "ipConfigurations": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'ipConfigurations')]" + }, + "applicationSecurityGroupResourceIds": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'applicationSecurityGroupResourceIds')]" + }, + "customNetworkInterfaceName": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'customNetworkInterfaceName')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "4120048060064073955" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "ipConfigurationsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the resource that is unique within a resource group." + } + }, + "properties": { + "type": "object", + "properties": { + "groupId": { + "type": "string", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "memberName": { + "type": "string", + "metadata": { + "description": "Required. The member name of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateIPAddress": { + "type": "string", + "metadata": { + "description": "Required. A private IP address obtained from the private endpoint's subnet." + } + } + }, + "metadata": { + "description": "Required. Properties of private endpoint IP configurations." + } + } + } + }, + "nullable": true + }, + "manualPrivateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "privateLinkServiceConnectionsType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the private link service connection." + } + }, + "properties": { + "type": "object", + "properties": { + "groupIds": { + "type": "array", + "metadata": { + "description": "Required. The ID of a group obtained from the remote resource that this private endpoint should connect to." + } + }, + "privateLinkServiceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of private link service." + } + }, + "requestMessage": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. A message passed to the owner of the remote resource with this connection request. Restricted to 140 chars." + } + } + }, + "metadata": { + "description": "Required. Properties of private link service connection." + } + } + } + }, + "nullable": true + }, + "customDnsConfigType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "metadata": { + "description": "Required. Fqdn that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "Required. A list of private IP addresses of the private endpoint." + } + } + } + }, + "nullable": true + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the private endpoint resource to create." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "applicationSecurityGroupResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. Application security groups in which the private endpoint IP configuration is included." + } + }, + "customNetworkInterfaceName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The custom name of the network interface attached to the private endpoint." + } + }, + "ipConfigurations": { + "$ref": "#/definitions/ipConfigurationsType", + "metadata": { + "description": "Optional. A list of IP configurations of the private endpoint. This will be used to map to the First Party Service endpoints." + } + }, + "privateDnsZoneGroupName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided." + } + }, + "privateDnsZoneResourceIds": { + "type": "array", + "nullable": true, + "metadata": { + "description": "Optional. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "$ref": "#/definitions/roleAssignmentType", + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags to be applied on all resources/resource groups in this deployment." + } + }, + "customDnsConfigs": { + "$ref": "#/definitions/customDnsConfigType", + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "$ref": "#/definitions/manualPrivateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource. Used when the network admin does not have access to approve connections to the remote resource." + } + }, + "privateLinkServiceConnections": { + "$ref": "#/definitions/privateLinkServiceConnectionsType", + "metadata": { + "description": "Optional. A grouping of information about the connection to the remote resource." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "DNS Resolver Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '0f2ebee7-ffd4-4fc0-b3b7-664099fdad5d')]", + "DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'befefa01-2a29-4197-83a8-272ff33ce314')]", + "Domain Services Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'eeaeda52-9324-47f6-8069-5d5bade478b2')]", + "Domain Services Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '361898ef-9ed1-48c2-849c-a832951106bb')]", + "Network Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '4d97b98b-1d4f-4787-a291-c67834d212e7')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.4.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "privateEndpoint": { + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-04-01", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "properties": { + "copy": [ + { + "name": "applicationSecurityGroups", + "count": "[length(coalesce(parameters('applicationSecurityGroupResourceIds'), createArray()))]", + "input": { + "id": "[coalesce(parameters('applicationSecurityGroupResourceIds'), createArray())[copyIndex('applicationSecurityGroups')]]" + } + } + ], + "customDnsConfigs": "[coalesce(parameters('customDnsConfigs'), createArray())]", + "customNetworkInterfaceName": "[coalesce(parameters('customNetworkInterfaceName'), '')]", + "ipConfigurations": "[coalesce(parameters('ipConfigurations'), createArray())]", + "manualPrivateLinkServiceConnections": "[coalesce(parameters('manualPrivateLinkServiceConnections'), createArray())]", + "privateLinkServiceConnections": "[coalesce(parameters('privateLinkServiceConnections'), createArray())]", + "subnet": { + "id": "[parameters('subnetResourceId')]" + } + } + }, + "privateEndpoint_lock": { + "condition": "[and(not(empty(coalesce(parameters('lock'), createObject()))), not(equals(tryGet(parameters('lock'), 'kind'), 'None')))]", + "type": "Microsoft.Authorization/locks", + "apiVersion": "2020-05-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(parameters('lock'), 'name'), format('lock-{0}', parameters('name')))]", + "properties": { + "level": "[coalesce(tryGet(parameters('lock'), 'kind'), '')]", + "notes": "[if(equals(tryGet(parameters('lock'), 'kind'), 'CanNotDelete'), 'Cannot delete resource or child resources.', 'Cannot delete or modify the resource or child resources.')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_roleAssignments": { + "copy": { + "name": "privateEndpoint_roleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Network/privateEndpoints/{0}', parameters('name'))]", + "name": "[guid(resourceId('Microsoft.Network/privateEndpoints', parameters('name')), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId, coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)]", + "properties": { + "roleDefinitionId": "[if(contains(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName), variables('builtInRoleNames')[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName], if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex()].roleDefinitionIdOrName)))]", + "principalId": "[coalesce(parameters('roleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(parameters('roleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "privateEndpoint" + ] + }, + "privateEndpoint_privateDnsZoneGroup": { + "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" + }, + "privateDNSResourceIds": { + "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + }, + "privateEndpointName": { + "value": "[parameters('name')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.25.53.49325", + "templateHash": "11244630631275470040" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "privateEndpointName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." + } + }, + "privateDNSResourceIds": { + "type": "array", + "minLength": 1, + "maxLength": 5, + "metadata": { + "description": "Required. Array of private DNS zone resource IDs. A DNS zone group can support up to 5 DNS zones." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "metadata": { + "description": "Optional. The name of the private DNS zone group." + } + } + }, + "variables": { + "copy": [ + { + "name": "privateDnsZoneConfigs", + "count": "[length(parameters('privateDNSResourceIds'))]", + "input": { + "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "properties": { + "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + } + } + } + ] + }, + "resources": [ + { + "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", + "apiVersion": "2023-04-01", + "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", + "properties": { + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint DNS zone group." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint DNS zone group." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints/privateDnsZoneGroups', parameters('privateEndpointName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint DNS zone group was deployed into." + }, + "value": "[resourceGroup().name]" + } + } + } + }, + "dependsOn": [ + "privateEndpoint" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the private endpoint was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + }, + "value": "[resourceId('Microsoft.Network/privateEndpoints', parameters('name'))]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + }, + "value": "[parameters('name')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('privateEndpoint', '2023-04-01', 'full').location]" + }, + "groupId": { + "type": "string", + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[if(not(empty(reference('privateEndpoint').manualPrivateLinkServiceConnections)), reference('privateEndpoint').manualPrivateLinkServiceConnections[0].properties.groupIds[0], reference('privateEndpoint').privateLinkServiceConnections[0].properties.groupIds[0])]" + } + } + } + }, + "dependsOn": [ + "keyVault" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the key vault." + }, + "value": "[resourceId('Microsoft.KeyVault/vaults', parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the key vault was created in." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the key vault." + }, + "value": "[parameters('name')]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The URI of the key vault." + }, + "value": "[reference('keyVault').vaultUri]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('keyVault', '2022-07-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "managedCluster" + ] + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the application insights components were deployed into." + }, + "value": "[resourceGroup().name]" + }, + "managedClusterName": { + "type": "string", + "metadata": { + "description": "The resource name of the AKS cluster." + }, + "value": "[reference('managedCluster').outputs.name.value]" + }, + "managedClusterClientId": { + "type": "string", + "metadata": { + "description": "The Client ID of the AKS identity." + }, + "value": "[reference('managedCluster').outputs.kubeletIdentityClientId.value]" + }, + "managedClusterObjectId": { + "type": "string", + "metadata": { + "description": "The Object ID of the AKS identity." + }, + "value": "[reference('managedCluster').outputs.kubeletIdentityObjectId.value]" + }, + "managedClusterResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the AKS cluster." + }, + "value": "[reference('managedCluster').outputs.kubeletIdentityResourceId.value]" + }, + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "The resource name of the ACR." + }, + "value": "[reference('containerRegistry').outputs.name.value]" + }, + "containerRegistryLoginServer": { + "type": "string", + "metadata": { + "description": "The login server for the container registry." + }, + "value": "[reference('containerRegistry').outputs.loginServer.value]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/aks/tests/e2e/defaults/dependencies.bicep b/avm/ptn/azd/aks/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..9961f0c426 --- /dev/null +++ b/avm/ptn/azd/aks/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,56 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the App Service to create.') +param appName string + +@description('Required. The name of the App Service Plan to create.') +param appServicePlanName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { + name: logAnalyticsWorkspaceName + location: location + properties: { + retentionInDays: 30 + features: { + searchVersion: 1 + } + sku: { + name: 'PerGB2018' + } + } +} + +resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { + name: appServicePlanName + location: location + sku: { + name: 'B3' + } + properties: { + reserved: true + } +} + +resource app 'Microsoft.Web/sites@2022-09-01' = { + name: appName + location: location + kind: 'app,linux' + properties: { + serverFarmId: appServicePlan.id + siteConfig: { + linuxFxVersion: 'dotnetcore|8.0' + alwaysOn: true + } + } + identity: { type: 'SystemAssigned' } +} + +@description('The app identity Principal Id.') +output identityPrincipalId string = app.identity.principalId + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.name diff --git a/avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..0e40826546 --- /dev/null +++ b/avm/ptn/azd/aks/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,63 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-azd-aks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'paamin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-dependencies' + scope: resourceGroup + params: { + location: resourceLocation + appName: 'dep-${namePrefix}-app-${serviceShort}' + appServicePlanName: 'dep-${namePrefix}-apps-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: 'mc${uniqueString(deployment().name)}-${serviceShort}' + containerRegistryName: '${uniqueString(deployment().name, resourceLocation)}testcontainerregistry${serviceShort}' + logAnalyticsName: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + keyVaultName: 'kv${uniqueString(deployment().name)}-${serviceShort}' + location: resourceLocation + principalId: nestedDependencies.outputs.identityPrincipalId + } + } +] diff --git a/avm/ptn/azd/aks/tests/e2e/max/dependencies.bicep b/avm/ptn/azd/aks/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..9961f0c426 --- /dev/null +++ b/avm/ptn/azd/aks/tests/e2e/max/dependencies.bicep @@ -0,0 +1,56 @@ +@description('Optional. The location to deploy to.') +param location string = resourceGroup().location + +@description('Required. The name of the App Service to create.') +param appName string + +@description('Required. The name of the App Service Plan to create.') +param appServicePlanName string + +@description('Required. The name of the Log Analytics Workspace to create.') +param logAnalyticsWorkspaceName string + +resource logAnalyticsWorkspace 'Microsoft.OperationalInsights/workspaces@2022-10-01' = { + name: logAnalyticsWorkspaceName + location: location + properties: { + retentionInDays: 30 + features: { + searchVersion: 1 + } + sku: { + name: 'PerGB2018' + } + } +} + +resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = { + name: appServicePlanName + location: location + sku: { + name: 'B3' + } + properties: { + reserved: true + } +} + +resource app 'Microsoft.Web/sites@2022-09-01' = { + name: appName + location: location + kind: 'app,linux' + properties: { + serverFarmId: appServicePlan.id + siteConfig: { + linuxFxVersion: 'dotnetcore|8.0' + alwaysOn: true + } + } + identity: { type: 'SystemAssigned' } +} + +@description('The app identity Principal Id.') +output identityPrincipalId string = app.identity.principalId + +@description('The resource ID of the created Log Analytics Workspace.') +output logAnalyticsWorkspaceResourceId string = logAnalyticsWorkspace.name diff --git a/avm/ptn/azd/aks/tests/e2e/max/main.test.bicep b/avm/ptn/azd/aks/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..964c796fff --- /dev/null +++ b/avm/ptn/azd/aks/tests/e2e/max/main.test.bicep @@ -0,0 +1,87 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-azd-aks-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'paamax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') +param containerRegistryRoleName string = newGuid() + +@description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') +param aksClusterRoleAssignmentName string = newGuid() + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + name: '${uniqueString(deployment().name, resourceLocation)}-test-dependencies' + scope: resourceGroup + params: { + location: resourceLocation + appName: 'dep-${namePrefix}-app-${serviceShort}' + appServicePlanName: 'dep-${namePrefix}-apps-${serviceShort}' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: 'mc${uniqueString(deployment().name)}-${serviceShort}' + containerRegistryName: '${uniqueString(deployment().name, resourceLocation)}testcontainerregistry${serviceShort}' + skuTier: 'Free' + webApplicationRoutingEnabled: true + agentPools: [ + { + name: 'npuserpool' + mode: 'User' + osType: 'Linux' + maxPods: 30 + type: 'VirtualMachineScaleSets' + maxSurge: '33%' + vmSize: 'standard_a2' + } + ] + logAnalyticsName: nestedDependencies.outputs.logAnalyticsWorkspaceResourceId + keyVaultName: 'kv${uniqueString(deployment().name)}-${serviceShort}' + location: resourceLocation + principalId: nestedDependencies.outputs.identityPrincipalId + acrSku: 'Basic' + dnsPrefix: 'dep-${namePrefix}-dns-${serviceShort}' + principalType: 'ServicePrincipal' + containerRegistryRoleName: containerRegistryRoleName + aksClusterRoleAssignmentName: aksClusterRoleAssignmentName + } + } +] diff --git a/avm/ptn/azd/aks/version.json b/avm/ptn/azd/aks/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/aks/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From d863654c67f7e92f628a38901ee088579772c608 Mon Sep 17 00:00:00 2001 From: Erika Gressi <56914614+eriqua@users.noreply.github.com> Date: Fri, 11 Oct 2024 11:32:04 +0200 Subject: [PATCH 12/17] fix: Cognitive services small update to trigger publishing (#3513) ## Description Small update to trigger publishing ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.cognitive-services.account](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml/badge.svg?branch=users%2Feriqua%2Fcog-ser-pub)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.cognitive-services.account.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [ ] I'm sure there are no other open Pull Requests for the same update/change - [ ] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- avm/res/cognitive-services/account/README.md | 4 ++-- avm/res/cognitive-services/account/main.bicep | 2 +- avm/res/cognitive-services/account/main.json | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index 9462bf4a9b..a2c4698c2e 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -1646,7 +1646,7 @@ param tags = { | [`restrictOutboundNetworkAccess`](#parameter-restrictoutboundnetworkaccess) | bool | Restrict outbound network access. | | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. | | [`secretsExportConfiguration`](#parameter-secretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | -| [`sku`](#parameter-sku) | string | SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. | +| [`sku`](#parameter-sku) | string | SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. | | [`tags`](#parameter-tags) | object | Tags of the resource. | | [`userOwnedStorage`](#parameter-userownedstorage) | array | The storage accounts for this resource. | @@ -2685,7 +2685,7 @@ The name for the accessKey2 secret to create. ### Parameter: `sku` -SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. +SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region. - Required: No - Type: string diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 96147cc72d..8dbadcfb78 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -34,7 +34,7 @@ param name string ]) param kind string -@description('Optional. SKU of the Cognitive Services resource. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') +@description('Optional. SKU of the Cognitive Services account. Use \'Get-AzCognitiveServicesAccountSku\' to determine a valid combinations of \'kind\' and \'SKU\' for your Azure region.') @allowed([ 'C2' 'C3' diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index 013a5b598c..b1c8468f51 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "9722036366573656954" + "templateHash": "4946778004284930976" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -694,7 +694,7 @@ "S9" ], "metadata": { - "description": "Optional. SKU of the Cognitive Services resource. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." + "description": "Optional. SKU of the Cognitive Services account. Use 'Get-AzCognitiveServicesAccountSku' to determine a valid combinations of 'kind' and 'SKU' for your Azure region." } }, "location": { From b5ce0f2816e601df2b26b114ac161440a9a067f0 Mon Sep 17 00:00:00 2001 From: "Menghua Chen (MSFT)" <111940661+Menghua1@users.noreply.github.com> Date: Fri, 11 Oct 2024 17:42:18 +0800 Subject: [PATCH 13/17] fix: Update the module identifiers in the issue template to the correct alphabetical order. (#3514) ## Description Fixes pipeline issue https://github.com/Azure/bicep-registry-modules/actions/runs/11288332565/job/31395906879. ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.ml-project](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml/badge.svg?branch=fix-pipeline-issue)](https://github.com/Menghua1/bicep-registry-modules/actions/workflows/avm.ptn.azd.ml-project.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --------- Co-authored-by: Erika Gressi <56914614+eriqua@users.noreply.github.com> --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f5002e3373..98b755c430 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -17,8 +17,8 @@ /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep -/avm/ptn/azd/ml-project/ @Azure/avm-ptn-azd-mlproject-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/ml-hub-dependencies/ @Azure/avm-ptn-azd-mlhubdependencies-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/ml-project/ @Azure/avm-ptn-azd-mlproject-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/monitoring/ @Azure/avm-ptn-azd-monitoring-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/deployment-script/import-image-to-acr/ @Azure/avm-ptn-deploymentscript-importimagetoacr-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/dev-ops/cicd-agents-and-runners/ @Azure/avm-ptn-devops-cicdagentsandrunners-module-owners-bicep @Azure/avm-module-reviewers-bicep From fdfb2e6f1b44ba52fe38566353a0b2c9a60e0118 Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Fri, 11 Oct 2024 13:49:59 +0200 Subject: [PATCH 14/17] fix: Container-Instace - Updated parameter type to be more specific (#3392) ## Description Updated DNS servers parameter to be a string array instead of just an array as it's the type in the API ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.container-instance.container-group](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml/badge.svg?branch=users%2Falsehr%2Fcontainer-app-version&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.container-instance.container-group.yml) | --- avm/res/container-instance/container-group/main.bicep | 2 +- avm/res/container-instance/container-group/main.json | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/avm/res/container-instance/container-group/main.bicep b/avm/res/container-instance/container-group/main.bicep index 5e0dec8fcd..2baee0b1d1 100644 --- a/avm/res/container-instance/container-group/main.bicep +++ b/avm/res/container-instance/container-group/main.bicep @@ -49,7 +49,7 @@ param autoGeneratedDomainNameLabelScope string = 'TenantReuse' param dnsNameLabel string? @description('Optional. List of dns servers used by the containers for lookups.') -param dnsNameServers array? +param dnsNameServers string[]? @description('Optional. DNS search domain which will be appended to each DNS lookup.') param dnsSearchDomains string? diff --git a/avm/res/container-instance/container-group/main.json b/avm/res/container-instance/container-group/main.json index ad6b40f5e8..7b1c128ccd 100644 --- a/avm/res/container-instance/container-group/main.json +++ b/avm/res/container-instance/container-group/main.json @@ -5,8 +5,8 @@ "metadata": { "_generator": { "name": "bicep", - "version": "0.28.1.47646", - "templateHash": "4541932168440754260" + "version": "0.30.23.60470", + "templateHash": "14261370383859328082" }, "name": "Container Instances Container Groups", "description": "This module deploys a Container Instance Container Group.", @@ -536,6 +536,9 @@ }, "dnsNameServers": { "type": "array", + "items": { + "type": "string" + }, "nullable": true, "metadata": { "description": "Optional. List of dns servers used by the containers for lookups." From 0ef32a0de24db13e094f2024cb397853cf6bb62b Mon Sep 17 00:00:00 2001 From: Alexander Sehr Date: Fri, 11 Oct 2024 20:56:07 +0200 Subject: [PATCH 15/17] feat: DevOpsPool - Fixed parameter requirement for images (#3401) ## Description - Fixed the requirement for the image parameter to allow the usage of a compute gallery image Example from portal deployment ![image](https://github.com/user-attachments/assets/d6a304eb-bc27-4d71-8411-cd62eeb42e2b) Exported JSON ```json "images": [ { "resourceId": "/Subscriptions/b765c5e5-ae60-4724-9b59-36fbcf56795b/Providers/Microsoft.Compute/Locations/westeurope/publishers/microsoftwindowsdesktop/artifacttypes/vmimage/offers/windows-11/skus/win11-22h2-pro/versions/latest", "buffer": "*" }, { "wellKnownImageName": "ubuntu-22.04/latest", "buffer": "*", "aliases": [ "ubuntu-22.04" ] }, { "resourceId": "/subscriptions/b765c5e5-ae60-4724-9b59-36fbcf56795b/resourceGroups/rg-ado-agents/providers/Microsoft.Compute/galleries/galaib/images/sid-linux/versions/latest", "buffer": "*" } ] ``` ## Pipeline Reference | Pipeline | | -------- | | [![avm.res.dev-ops-infrastructure.pool](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml/badge.svg?branch=users%2Falsehr%2FdevopsPoolImageFix&event=workflow_dispatch)](https://github.com/Azure/bicep-registry-modules/actions/workflows/avm.res.dev-ops-infrastructure.pool.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [ ] Azure Verified Module updates: - [x] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation --- avm/res/dev-ops-infrastructure/pool/README.md | 24 ++-- .../dev-ops-infrastructure/pool/main.bicep | 24 +++- avm/res/dev-ops-infrastructure/pool/main.json | 123 ++++++++++++------ 3 files changed, 114 insertions(+), 57 deletions(-) diff --git a/avm/res/dev-ops-infrastructure/pool/README.md b/avm/res/dev-ops-infrastructure/pool/README.md index dee3ec1d9f..9896670d02 100644 --- a/avm/res/dev-ops-infrastructure/pool/README.md +++ b/avm/res/dev-ops-infrastructure/pool/README.md @@ -810,11 +810,12 @@ The VM images of the machines in the pool. - Required: Yes - Type: array -**Required parameters** +**Conditional parameters** | Parameter | Type | Description | | :-- | :-- | :-- | -| [`wellKnownImageName`](#parameter-imageswellknownimagename) | string | The image to use from a well-known set of images made available to customers. | +| [`resourceId`](#parameter-imagesresourceid) | string | The specific resource id of the marketplace or compute gallery image. Required if `wellKnownImageName` is not set. | +| [`wellKnownImageName`](#parameter-imageswellknownimagename) | string | The image to use from a well-known set of images made available to customers. Required if `resourceId` is not set. | **Optional parameters** @@ -822,13 +823,19 @@ The VM images of the machines in the pool. | :-- | :-- | :-- | | [`aliases`](#parameter-imagesaliases) | array | List of aliases to reference the image by. | | [`buffer`](#parameter-imagesbuffer) | string | The percentage of the buffer to be allocated to this image. | -| [`resourceId`](#parameter-imagesresourceid) | string | The resource id of the image. | + +### Parameter: `images.resourceId` + +The specific resource id of the marketplace or compute gallery image. Required if `wellKnownImageName` is not set. + +- Required: No +- Type: string ### Parameter: `images.wellKnownImageName` -The image to use from a well-known set of images made available to customers. +The image to use from a well-known set of images made available to customers. Required if `resourceId` is not set. -- Required: Yes +- Required: No - Type: string ### Parameter: `images.aliases` @@ -845,13 +852,6 @@ The percentage of the buffer to be allocated to this image. - Required: No - Type: string -### Parameter: `images.resourceId` - -The resource id of the image. - -- Required: No -- Type: string - ### Parameter: `name` Name of the pool. It needs to be globally unique. diff --git a/avm/res/dev-ops-infrastructure/pool/main.bicep b/avm/res/dev-ops-infrastructure/pool/main.bicep index af61e650fe..358dd0abf5 100644 --- a/avm/res/dev-ops-infrastructure/pool/main.bicep +++ b/avm/res/dev-ops-infrastructure/pool/main.bicep @@ -14,7 +14,7 @@ param fabricProfileSkuName string param concurrency int @description('Required. The VM images of the machines in the pool.') -param images imageType +param images imageType[] @description('Optional. The geo-location where the resource lives.') param location string = resourceGroup().location @@ -235,6 +235,7 @@ output location string = managedDevOpsPool.location @description('The principal ID of the system assigned identity.') output systemAssignedMIPrincipalId string? = managedDevOpsPool.?identity.?principalId +@export() type osProfileType = { @description('Required. The logon type of the machine.') logonType: ('Interactive' | 'Service') @@ -252,6 +253,7 @@ type osProfileType = { }? } +@export() type storageProfileType = { @description('Optional. The Azure SKU name of the machines in the pool.') osDiskStorageAccountType: ('Premium' | 'StandardSSD' | 'Standard')? @@ -272,6 +274,7 @@ type storageProfileType = { }[]? }? +@export() type imageType = { @description('Optional. List of aliases to reference the image by.') aliases: string[]? @@ -279,13 +282,14 @@ type imageType = { @description('Optional. The percentage of the buffer to be allocated to this image.') buffer: string? - @description('Required. The image to use from a well-known set of images made available to customers.') - wellKnownImageName: string + @description('Conditional. The image to use from a well-known set of images made available to customers. Required if `resourceId` is not set.') + wellKnownImageName: string? - @description('Optional. The resource id of the image.') + @description('Conditional. The specific resource id of the marketplace or compute gallery image. Required if `wellKnownImageName` is not set.') resourceId: string? -}[] +} +@export() type organizationProfileType = { @description('Required. Azure DevOps organization profile.') kind: 'AzureDevOps' @@ -317,6 +321,7 @@ type organizationProfileType = { }[] } +@export() type dataDiskType = { @description('Optional. The type of caching to be enabled for the data disks. The default value for caching is readwrite. For information about the caching options see: https://blogs.msdn.microsoft.com/windowsazurestorage/2012/06/27/exploring-windows-azure-drives-disks-and-images/.') caching: ('None' | 'ReadOnly' | 'ReadWrite')? @@ -331,6 +336,7 @@ type dataDiskType = { storageAccountType: ('Premium_LRS' | 'Premium_ZRS' | 'StandardSSD_LRS' | 'StandardSSD_ZRS' | 'Standard_LRS')? }[]? +@export() type resourcePredictionsProfileAutomaticType = { @description('Required. The stand-by agent scheme is determined based on historical demand.') kind: 'Automatic' @@ -339,11 +345,13 @@ type resourcePredictionsProfileAutomaticType = { predictionPreference: 'Balanced' | 'MostCostEffective' | 'MoreCostEffective' | 'MorePerformance' | 'BestPerformance' } +@export() type resourcePredictionsProfileManualType = { @description('Required. Customer provides the stand-by agent scheme.') kind: 'Manual' } +@export() type agentStatefulType = { @description('Required. Stateful profile meaning that the machines will be returned to the pool after running a job.') kind: 'Stateful' @@ -362,6 +370,7 @@ type agentStatefulType = { resourcePredictionsProfile: (resourcePredictionsProfileAutomaticType | resourcePredictionsProfileManualType)? } +@export() type agentStatelessType = { @description('Required. Stateless profile meaning that the machines will be cleaned up after running a job.') kind: 'Stateless' @@ -400,8 +409,10 @@ type agentStatelessType = { } @discriminator('kind') +@export() type agentProfileType = agentStatefulType | agentStatelessType +@export() type roleAssignmentType = { @description('Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated.') name: string? @@ -428,6 +439,7 @@ type roleAssignmentType = { delegatedManagedIdentityResourceId: string? }[]? +@export() type lockType = { @description('Optional. Specify the name of lock.') name: string? @@ -436,6 +448,7 @@ type lockType = { kind: ('CanNotDelete' | 'ReadOnly' | 'None')? }? +@export() type diagnosticSettingType = { @description('Optional. The name of diagnostic setting.') name: string? @@ -480,6 +493,7 @@ type diagnosticSettingType = { marketplacePartnerResourceId: string? }[]? +@export() type managedIdentitiesType = { @description('Optional. Enables system assigned managed identity on the resource.') systemAssigned: bool? diff --git a/avm/res/dev-ops-infrastructure/pool/main.json b/avm/res/dev-ops-infrastructure/pool/main.json index 689ef6eb8c..05c3db9232 100644 --- a/avm/res/dev-ops-infrastructure/pool/main.json +++ b/avm/res/dev-ops-infrastructure/pool/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "3502193398932835678" + "templateHash": "14560645908978883645" }, "name": "Managed DevOps Pool", "description": "This module deploys the Managed DevOps Pool resource.", @@ -57,6 +57,9 @@ "description": "Optional. The secret management settings of the machines in the pool." } } + }, + "metadata": { + "__bicep_export!": true } }, "storageProfileType": { @@ -127,44 +130,48 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "imageType": { - "type": "array", - "items": { - "type": "object", - "properties": { - "aliases": { - "type": "array", - "items": { - "type": "string" - }, - "nullable": true, - "metadata": { - "description": "Optional. List of aliases to reference the image by." - } - }, - "buffer": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The percentage of the buffer to be allocated to this image." - } - }, - "wellKnownImageName": { - "type": "string", - "metadata": { - "description": "Required. The image to use from a well-known set of images made available to customers." - } + "type": "object", + "properties": { + "aliases": { + "type": "array", + "items": { + "type": "string" }, - "resourceId": { - "type": "string", - "nullable": true, - "metadata": { - "description": "Optional. The resource id of the image." - } + "nullable": true, + "metadata": { + "description": "Optional. List of aliases to reference the image by." + } + }, + "buffer": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The percentage of the buffer to be allocated to this image." + } + }, + "wellKnownImageName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The image to use from a well-known set of images made available to customers. Required if `resourceId` is not set." + } + }, + "resourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Conditional. The specific resource id of the marketplace or compute gallery image. Required if `wellKnownImageName` is not set." } } + }, + "metadata": { + "__bicep_export!": true } }, "organizationProfileType": { @@ -255,6 +262,9 @@ "description": "Required. The list of Azure DevOps organizations the pool should be present in.." } } + }, + "metadata": { + "__bicep_export!": true } }, "dataDiskType": { @@ -304,7 +314,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "resourcePredictionsProfileAutomaticType": { "type": "object", @@ -331,6 +344,9 @@ "description": "Required. Determines the balance between cost and performance." } } + }, + "metadata": { + "__bicep_export!": true } }, "resourcePredictionsProfileManualType": { @@ -345,6 +361,9 @@ "description": "Required. Customer provides the stand-by agent scheme." } } + }, + "metadata": { + "__bicep_export!": true } }, "agentStatefulType": { @@ -396,6 +415,9 @@ "description": "Optional. Determines how the stand-by scheme should be provided." } } + }, + "metadata": { + "__bicep_export!": true } }, "agentStatelessType": { @@ -454,6 +476,9 @@ "description": "Optional. Determines how the stand-by scheme should be provided." } } + }, + "metadata": { + "__bicep_export!": true } }, "agentProfileType": { @@ -468,6 +493,9 @@ "$ref": "#/definitions/agentStatelessType" } } + }, + "metadata": { + "__bicep_export!": true } }, "roleAssignmentType": { @@ -541,7 +569,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "lockType": { "type": "object", @@ -566,7 +597,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "diagnosticSettingType": { "type": "array", @@ -686,7 +720,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } }, "managedIdentitiesType": { "type": "object", @@ -709,7 +746,10 @@ } } }, - "nullable": true + "nullable": true, + "metadata": { + "__bicep_export!": true + } } }, "parameters": { @@ -734,7 +774,10 @@ } }, "images": { - "$ref": "#/definitions/imageType", + "type": "array", + "items": { + "$ref": "#/definitions/imageType" + }, "metadata": { "description": "Required. The VM images of the machines in the pool." } From 4b99f59014f613d924139ad8dface53e32e1f4a9 Mon Sep 17 00:00:00 2001 From: "Shihua Xiong (MSFT)" <138103031+NanaXiong00@users.noreply.github.com> Date: Sat, 12 Oct 2024 16:33:22 +0800 Subject: [PATCH 16/17] feat: Add new ptn modules `avm/ptn/azd/container-app-upsert` (#3260) ## Description Fixes https://github.com/Azure/Azure-Verified-Modules/issues/1222 ## Pipeline Reference | Pipeline | | -------- | | [![avm.ptn.azd.container-app-upsert](https://github.com/NanaXiong00/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-app-upsert.yml/badge.svg?branch=ptn%2Fazd%2Fcontainer-app-upsert)](https://github.com/NanaXiong00/bicep-registry-modules/actions/workflows/avm.ptn.azd.container-app-upsert.yml) | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [ ] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [x] My corresponding pipelines / checks run clean and green without any errors or warnings @jongio for notification. --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .../avm.ptn.azd.container-app-upsert.yml | 88 + avm/ptn/azd/container-app-upsert/README.md | 616 +++++ avm/ptn/azd/container-app-upsert/main.bicep | 177 ++ avm/ptn/azd/container-app-upsert/main.json | 2179 +++++++++++++++++ .../tests/e2e/defaults/dependencies.bicep | 14 + .../tests/e2e/defaults/main.test.bicep | 58 + .../tests/e2e/max/dependencies.bicep | 120 + .../tests/e2e/max/main.test.bicep | 101 + avm/ptn/azd/container-app-upsert/version.json | 7 + 11 files changed, 3362 insertions(+) create mode 100644 .github/workflows/avm.ptn.azd.container-app-upsert.yml create mode 100644 avm/ptn/azd/container-app-upsert/README.md create mode 100644 avm/ptn/azd/container-app-upsert/main.bicep create mode 100644 avm/ptn/azd/container-app-upsert/main.json create mode 100644 avm/ptn/azd/container-app-upsert/tests/e2e/defaults/dependencies.bicep create mode 100644 avm/ptn/azd/container-app-upsert/tests/e2e/defaults/main.test.bicep create mode 100644 avm/ptn/azd/container-app-upsert/tests/e2e/max/dependencies.bicep create mode 100644 avm/ptn/azd/container-app-upsert/tests/e2e/max/main.test.bicep create mode 100644 avm/ptn/azd/container-app-upsert/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 98b755c430..07a798c38d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -15,6 +15,7 @@ /avm/ptn/azd/acr-container-app/ @Azure/avm-ptn-azd-acrcontainerapp-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/aks/ @Azure/avm-ptn-azd-aks-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/apim-api/ @Azure/avm-ptn-azd-apimapi-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/ptn/azd/container-app-upsert/ @Azure/avm-ptn-azd-containerappupsert-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/container-apps-stack/ @Azure/avm-ptn-azd-containerappsstack-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/insights-dashboard/ @Azure/avm-ptn-azd-insightsdashboard-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/ptn/azd/ml-hub-dependencies/ @Azure/avm-ptn-azd-mlhubdependencies-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index 2d27f5792e..4fdaa41ac2 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -50,6 +50,7 @@ body: - "avm/ptn/azd/acr-container-app" - "avm/ptn/azd/aks" - "avm/ptn/azd/apim-api" + - "avm/ptn/azd/container-app-upsert" - "avm/ptn/azd/container-apps-stack" - "avm/ptn/azd/insights-dashboard" - "avm/ptn/azd/ml-hub-dependencies" diff --git a/.github/workflows/avm.ptn.azd.container-app-upsert.yml b/.github/workflows/avm.ptn.azd.container-app-upsert.yml new file mode 100644 index 0000000000..a612a7c55c --- /dev/null +++ b/.github/workflows/avm.ptn.azd.container-app-upsert.yml @@ -0,0 +1,88 @@ +name: "avm.ptn.azd.container-app-upsert" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.ptn.azd.container-app-upsert.yml" + - "avm/ptn/azd/container-app-upsert/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/ptn/azd/container-app-upsert" + workflowPath: ".github/workflows/avm.ptn.azd.container-app-upsert.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/ptn/azd/container-app-upsert/README.md b/avm/ptn/azd/container-app-upsert/README.md new file mode 100644 index 0000000000..5caa1cec82 --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/README.md @@ -0,0 +1,616 @@ +# Azd Container App Upsert `[Azd/ContainerAppUpsert]` + +Creates or updates an existing Azure Container App. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.App/containerApps` | [2024-03-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.App/2024-03-01/containerApps) | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/ptn/azd/container-app-upsert:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Using large parameter set](#example-2-using-large-parameter-set) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module containerAppUpsert 'br/public:avm/ptn/azd/container-app-upsert:' = { + name: 'containerAppUpsertDeployment' + params: { + // Required parameters + containerAppsEnvironmentName: '' + name: 'acaumin001' + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

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

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/container-app-upsert:' + +// Required parameters +param containerAppsEnvironmentName = '' +param name = 'acaumin001' +// Non-required parameters +param location = '' +``` + +
+

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

+ +via Bicep module + +```bicep +module containerAppUpsert 'br/public:avm/ptn/azd/container-app-upsert:' = { + name: 'containerAppUpsertDeployment' + params: { + // Required parameters + containerAppsEnvironmentName: '' + name: '' + // Non-required parameters + containerRegistryName: '' + daprEnabled: true + env: [ + { + name: 'ContainerAppStoredSecretName' + secretRef: 'containerappstoredsecret' + } + { + name: 'ContainerAppKeyVaultStoredSecretName' + secretRef: 'keyvaultstoredsecret' + } + ] + exists: true + identityName: '' + identityPrincipalId: '' + identityType: 'UserAssigned' + location: '' + secrets: { + secureList: [ + { + name: 'containerappstoredsecret' + value: '' + } + { + identity: '' + keyVaultUrl: '' + name: 'keyvaultstoredsecret' + } + ] + } + tags: { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' + } + userAssignedIdentityResourceId: '' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "containerAppsEnvironmentName": { + "value": "" + }, + "name": { + "value": "" + }, + // Non-required parameters + "containerRegistryName": { + "value": "" + }, + "daprEnabled": { + "value": true + }, + "env": { + "value": [ + { + "name": "ContainerAppStoredSecretName", + "secretRef": "containerappstoredsecret" + }, + { + "name": "ContainerAppKeyVaultStoredSecretName", + "secretRef": "keyvaultstoredsecret" + } + ] + }, + "exists": { + "value": true + }, + "identityName": { + "value": "" + }, + "identityPrincipalId": { + "value": "" + }, + "identityType": { + "value": "UserAssigned" + }, + "location": { + "value": "" + }, + "secrets": { + "value": { + "secureList": [ + { + "name": "containerappstoredsecret", + "value": "" + }, + { + "identity": "", + "keyVaultUrl": "", + "name": "keyvaultstoredsecret" + } + ] + } + }, + "tags": { + "value": { + "Env": "test", + "hidden-title": "This is visible in the resource name" + } + }, + "userAssignedIdentityResourceId": { + "value": "" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/ptn/azd/container-app-upsert:' + +// Required parameters +param containerAppsEnvironmentName = '' +param name = '' +// Non-required parameters +param containerRegistryName = '' +param daprEnabled = true +param env = [ + { + name: 'ContainerAppStoredSecretName' + secretRef: 'containerappstoredsecret' + } + { + name: 'ContainerAppKeyVaultStoredSecretName' + secretRef: 'keyvaultstoredsecret' + } +] +param exists = true +param identityName = '' +param identityPrincipalId = '' +param identityType = 'UserAssigned' +param location = '' +param secrets = { + secureList: [ + { + name: 'containerappstoredsecret' + value: '' + } + { + identity: '' + keyVaultUrl: '' + name: 'keyvaultstoredsecret' + } + ] +} +param tags = { + Env: 'test' + 'hidden-title': 'This is visible in the resource name' +} +param userAssignedIdentityResourceId = '' +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containerAppsEnvironmentName`](#parameter-containerappsenvironmentname) | string | Name of the environment for container apps. | +| [`name`](#parameter-name) | string | The name of the Container App. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`containerCpuCoreCount`](#parameter-containercpucorecount) | string | The number of CPU cores allocated to a single container instance, e.g., 0.5. | +| [`containerMaxReplicas`](#parameter-containermaxreplicas) | int | The maximum number of replicas to run. Must be at least 1. | +| [`containerMemory`](#parameter-containermemory) | string | The amount of memory allocated to a single container instance, e.g., 1Gi. | +| [`containerMinReplicas`](#parameter-containerminreplicas) | int | The minimum number of replicas to run. Must be at least 2. | +| [`containerName`](#parameter-containername) | string | The name of the container. | +| [`containerRegistryHostSuffix`](#parameter-containerregistryhostsuffix) | string | Hostname suffix for container registry. Set when deploying to sovereign clouds. | +| [`containerRegistryName`](#parameter-containerregistryname) | string | The name of the container registry. | +| [`daprAppId`](#parameter-daprappid) | string | The Dapr app ID. | +| [`daprAppProtocol`](#parameter-daprappprotocol) | string | The protocol used by Dapr to connect to the app, e.g., HTTP or gRPC. | +| [`daprEnabled`](#parameter-daprenabled) | bool | Enable or disable Dapr for the container app. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`env`](#parameter-env) | array | The environment variables for the container. | +| [`exists`](#parameter-exists) | bool | Specifies if the resource already exists. | +| [`external`](#parameter-external) | bool | Specifies if the resource ingress is exposed externally. | +| [`identityName`](#parameter-identityname) | string | The name of the user-assigned identity. | +| [`identityPrincipalId`](#parameter-identityprincipalid) | string | The principal ID of the principal to assign the role to. | +| [`identityType`](#parameter-identitytype) | string | The type of identity for the resource. | +| [`imageName`](#parameter-imagename) | string | The name of the container image. | +| [`ingressEnabled`](#parameter-ingressenabled) | bool | Specifies if Ingress is enabled for the container app. | +| [`location`](#parameter-location) | string | Location for all Resources. | +| [`secrets`](#parameter-secrets) | secureObject | The secrets required for the container. | +| [`serviceBinds`](#parameter-servicebinds) | array | The service binds associated with the container. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`targetPort`](#parameter-targetport) | int | The target port for the container. | +| [`userAssignedIdentityResourceId`](#parameter-userassignedidentityresourceid) | string | The resource id of the user-assigned identity. | + +### Parameter: `containerAppsEnvironmentName` + +Name of the environment for container apps. + +- Required: Yes +- Type: string + +### Parameter: `name` + +The name of the Container App. + +- Required: Yes +- Type: string + +### Parameter: `containerCpuCoreCount` + +The number of CPU cores allocated to a single container instance, e.g., 0.5. + +- Required: No +- Type: string +- Default: `'0.5'` + +### Parameter: `containerMaxReplicas` + +The maximum number of replicas to run. Must be at least 1. + +- Required: No +- Type: int +- Default: `10` + +### Parameter: `containerMemory` + +The amount of memory allocated to a single container instance, e.g., 1Gi. + +- Required: No +- Type: string +- Default: `'1.0Gi'` + +### Parameter: `containerMinReplicas` + +The minimum number of replicas to run. Must be at least 2. + +- Required: No +- Type: int +- Default: `2` + +### Parameter: `containerName` + +The name of the container. + +- Required: No +- Type: string +- Default: `'main'` + +### Parameter: `containerRegistryHostSuffix` + +Hostname suffix for container registry. Set when deploying to sovereign clouds. + +- Required: No +- Type: string +- Default: `'azurecr.io'` + +### Parameter: `containerRegistryName` + +The name of the container registry. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `daprAppId` + +The Dapr app ID. + +- Required: No +- Type: string +- Default: `[parameters('containerName')]` + +### Parameter: `daprAppProtocol` + +The protocol used by Dapr to connect to the app, e.g., HTTP or gRPC. + +- Required: No +- Type: string +- Default: `'http'` +- Allowed: + ```Bicep + [ + 'grpc' + 'http' + ] + ``` + +### Parameter: `daprEnabled` + +Enable or disable Dapr for the container app. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `enableTelemetry` + +Enable/Disable usage telemetry for module. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `env` + +The environment variables for the container. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-envname) | string | Environment variable name. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`secretRef`](#parameter-envsecretref) | string | Name of the Container App secret from which to pull the environment variable value. | +| [`value`](#parameter-envvalue) | string | Non-secret environment variable value. | + +### Parameter: `env.name` + +Environment variable name. + +- Required: Yes +- Type: string + +### Parameter: `env.secretRef` + +Name of the Container App secret from which to pull the environment variable value. + +- Required: No +- Type: string + +### Parameter: `env.value` + +Non-secret environment variable value. + +- Required: No +- Type: string + +### Parameter: `exists` + +Specifies if the resource already exists. + +- Required: No +- Type: bool +- Default: `False` + +### Parameter: `external` + +Specifies if the resource ingress is exposed externally. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `identityName` + +The name of the user-assigned identity. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `identityPrincipalId` + +The principal ID of the principal to assign the role to. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `identityType` + +The type of identity for the resource. + +- Required: No +- Type: string +- Default: `'None'` +- Allowed: + ```Bicep + [ + 'None' + 'SystemAssigned' + 'UserAssigned' + ] + ``` + +### Parameter: `imageName` + +The name of the container image. + +- Required: No +- Type: string +- Default: `''` + +### Parameter: `ingressEnabled` + +Specifies if Ingress is enabled for the container app. + +- Required: No +- Type: bool +- Default: `True` + +### Parameter: `location` + +Location for all Resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `secrets` + +The secrets required for the container. + +- Required: No +- Type: secureObject +- Default: `{}` + +### Parameter: `serviceBinds` + +The service binds associated with the container. + +- Required: No +- Type: array +- Default: `[]` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `targetPort` + +The target port for the container. + +- Required: No +- Type: int +- Default: `80` + +### Parameter: `userAssignedIdentityResourceId` + +The resource id of the user-assigned identity. + +- Required: No +- Type: string +- Default: `''` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `defaultDomain` | string | The Default domain of the Container App. | +| `imageName` | string | The name of the container image. | +| `name` | string | The name of the Container App. | +| `resourceGroupName` | string | The name of the resource group the Container App was deployed into. | +| `resourceId` | string | The resource ID of the Container App. | +| `uri` | string | The uri of the Container App. | + +## Cross-referenced modules + +This section gives you an overview of all local-referenced module files (i.e., other modules that are referenced in this module) and all remote-referenced files (i.e., Bicep modules that are referenced from a Bicep Registry or Template Specs). + +| Reference | Type | +| :-- | :-- | +| `br/public:avm/ptn/azd/acr-container-app:0.1.0` | Remote reference | + +## Data Collection + +The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the [repository](https://aka.ms/avm/telemetry). There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at . You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices. diff --git a/avm/ptn/azd/container-app-upsert/main.bicep b/avm/ptn/azd/container-app-upsert/main.bicep new file mode 100644 index 0000000000..17533fdf52 --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/main.bicep @@ -0,0 +1,177 @@ +metadata name = 'Azd Container App Upsert' +metadata description = '''Creates or updates an existing Azure Container App. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case''' +metadata owner = 'Azure/module-maintainers' + +@description('Required. The name of the Container App.') +param name string + +@description('Optional. Location for all Resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object? + +@description('Required. Name of the environment for container apps.') +param containerAppsEnvironmentName string + +@description('Optional. The number of CPU cores allocated to a single container instance, e.g., 0.5.') +param containerCpuCoreCount string = '0.5' + +@description('Optional. The maximum number of replicas to run. Must be at least 1.') +@minValue(1) +param containerMaxReplicas int = 10 + +@description('Optional. The amount of memory allocated to a single container instance, e.g., 1Gi.') +param containerMemory string = '1.0Gi' + +@description('Optional. The minimum number of replicas to run. Must be at least 2.') +@minValue(1) +param containerMinReplicas int = 2 + +@description('Optional. The name of the container.') +param containerName string = 'main' + +@description('Optional. The name of the container registry.') +param containerRegistryName string = '' + +@description('Optional. Hostname suffix for container registry. Set when deploying to sovereign clouds.') +param containerRegistryHostSuffix string = 'azurecr.io' + +@allowed(['http', 'grpc']) +@description('Optional. The protocol used by Dapr to connect to the app, e.g., HTTP or gRPC.') +param daprAppProtocol string = 'http' + +@description('Optional. Enable or disable Dapr for the container app.') +param daprEnabled bool = false + +@description('Optional. The Dapr app ID.') +param daprAppId string = containerName + +@description('Optional. Specifies if the resource already exists.') +param exists bool = false + +@description('Optional. Specifies if Ingress is enabled for the container app.') +param ingressEnabled bool = true + +@description('Optional. The type of identity for the resource.') +@allowed(['None', 'SystemAssigned', 'UserAssigned']) +param identityType string = 'None' + +@description('Optional. The name of the user-assigned identity.') +param identityName string = '' + +@description('Optional. The name of the container image.') +param imageName string = '' + +@description('Optional. The secrets required for the container.') +@secure() +param secrets object = {} + +@description('Optional. The environment variables for the container.') +param env environmentType[]? + +@description('Optional. Specifies if the resource ingress is exposed externally.') +param external bool = true + +@description('Optional. The service binds associated with the container.') +param serviceBinds array = [] + +@description('Optional. The target port for the container.') +param targetPort int = 80 + +@description('Optional. The principal ID of the principal to assign the role to.') +param identityPrincipalId string = '' + +@description('Optional. The resource id of the user-assigned identity.') +param userAssignedIdentityResourceId string = '' + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.ptn.azd-containerappupsert.${replace('-..--..-', '.', '-')}.${substring(uniqueString(deployment().name, location), 0, 4)}' + properties: { + mode: 'Incremental' + template: { + '$schema': 'https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#' + contentVersion: '1.0.0.0' + resources: [] + outputs: { + telemetry: { + type: 'String' + value: 'For more information, see https://aka.ms/avm/TelemetryInfo' + } + } + } + } +} + +resource existingApp 'Microsoft.App/containerApps@2023-05-02-preview' existing = if (exists) { + name: name +} + +module app 'br/public:avm/ptn/azd/acr-container-app:0.1.0' = { + name: '${uniqueString(deployment().name, location)}-container-app-update' + params: { + name: name + location: location + tags: tags + identityType: identityType + identityName: identityName + ingressEnabled: ingressEnabled + containerName: containerName + containerAppsEnvironmentName: containerAppsEnvironmentName + containerRegistryName: containerRegistryName + containerRegistryHostSuffix: containerRegistryHostSuffix + containerCpuCoreCount: containerCpuCoreCount + containerMemory: containerMemory + containerMinReplicas: containerMinReplicas + containerMaxReplicas: containerMaxReplicas + daprEnabled: daprEnabled + daprAppId: daprAppId + daprAppProtocol: daprAppProtocol + secrets: secrets + external: external + env: env + imageName: !empty(imageName) ? imageName : exists ? existingApp.properties.template.containers[0].image : '' + targetPort: targetPort + serviceBinds: serviceBinds + principalId: !empty(identityName) && !empty(containerRegistryName) ? identityPrincipalId : '' + userAssignedIdentityResourceId: !empty(identityName) && !empty(containerRegistryName) + ? userAssignedIdentityResourceId + : '' + enableTelemetry: enableTelemetry + } +} + +@description('The Default domain of the Container App.') +output defaultDomain string = app.outputs.defaultDomain + +@description('The name of the container image.') +output imageName string = app.outputs.imageName + +@description('The name of the Container App.') +output name string = app.outputs.name + +@description('The uri of the Container App.') +output uri string = app.outputs.uri + +@description('The resource ID of the Container App.') +output resourceId string = app.outputs.resourceId + +@description('The name of the resource group the Container App was deployed into.') +output resourceGroupName string = resourceGroup().name + +type environmentType = { + @description('Required. Environment variable name.') + name: string + + @description('Optional. Name of the Container App secret from which to pull the environment variable value.') + secretRef: string? + + @description('Optional. Non-secret environment variable value.') + value: string? +} diff --git a/avm/ptn/azd/container-app-upsert/main.json b/avm/ptn/azd/container-app-upsert/main.json new file mode 100644 index 0000000000..087916758f --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/main.json @@ -0,0 +1,2179 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "610733373146441190" + }, + "name": "Azd Container App Upsert", + "description": "Creates or updates an existing Azure Container App.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "environmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "containerAppsEnvironmentName": { + "type": "string", + "metadata": { + "description": "Required. Name of the environment for container apps." + } + }, + "containerCpuCoreCount": { + "type": "string", + "defaultValue": "0.5", + "metadata": { + "description": "Optional. The number of CPU cores allocated to a single container instance, e.g., 0.5." + } + }, + "containerMaxReplicas": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "metadata": { + "description": "Optional. The maximum number of replicas to run. Must be at least 1." + } + }, + "containerMemory": { + "type": "string", + "defaultValue": "1.0Gi", + "metadata": { + "description": "Optional. The amount of memory allocated to a single container instance, e.g., 1Gi." + } + }, + "containerMinReplicas": { + "type": "int", + "defaultValue": 2, + "minValue": 1, + "metadata": { + "description": "Optional. The minimum number of replicas to run. Must be at least 2." + } + }, + "containerName": { + "type": "string", + "defaultValue": "main", + "metadata": { + "description": "Optional. The name of the container." + } + }, + "containerRegistryName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container registry." + } + }, + "containerRegistryHostSuffix": { + "type": "string", + "defaultValue": "azurecr.io", + "metadata": { + "description": "Optional. Hostname suffix for container registry. Set when deploying to sovereign clouds." + } + }, + "daprAppProtocol": { + "type": "string", + "defaultValue": "http", + "allowedValues": [ + "http", + "grpc" + ], + "metadata": { + "description": "Optional. The protocol used by Dapr to connect to the app, e.g., HTTP or gRPC." + } + }, + "daprEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable or disable Dapr for the container app." + } + }, + "daprAppId": { + "type": "string", + "defaultValue": "[parameters('containerName')]", + "metadata": { + "description": "Optional. The Dapr app ID." + } + }, + "exists": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Specifies if the resource already exists." + } + }, + "ingressEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if Ingress is enabled for the container app." + } + }, + "identityType": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "None", + "SystemAssigned", + "UserAssigned" + ], + "metadata": { + "description": "Optional. The type of identity for the resource." + } + }, + "identityName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the user-assigned identity." + } + }, + "imageName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container image." + } + }, + "secrets": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The secrets required for the container." + } + }, + "env": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The environment variables for the container." + } + }, + "external": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the resource ingress is exposed externally." + } + }, + "serviceBinds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The service binds associated with the container." + } + }, + "targetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. The target port for the container." + } + }, + "identityPrincipalId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The principal ID of the principal to assign the role to." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource id of the user-assigned identity." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-containerappupsert.{0}.{1}', replace('-..--..-', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + "existingApp": { + "condition": "[parameters('exists')]", + "existing": true, + "type": "Microsoft.App/containerApps", + "apiVersion": "2023-05-02-preview", + "name": "[parameters('name')]" + }, + "app": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-container-app-update', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "identityType": { + "value": "[parameters('identityType')]" + }, + "identityName": { + "value": "[parameters('identityName')]" + }, + "ingressEnabled": { + "value": "[parameters('ingressEnabled')]" + }, + "containerName": { + "value": "[parameters('containerName')]" + }, + "containerAppsEnvironmentName": { + "value": "[parameters('containerAppsEnvironmentName')]" + }, + "containerRegistryName": { + "value": "[parameters('containerRegistryName')]" + }, + "containerRegistryHostSuffix": { + "value": "[parameters('containerRegistryHostSuffix')]" + }, + "containerCpuCoreCount": { + "value": "[parameters('containerCpuCoreCount')]" + }, + "containerMemory": { + "value": "[parameters('containerMemory')]" + }, + "containerMinReplicas": { + "value": "[parameters('containerMinReplicas')]" + }, + "containerMaxReplicas": { + "value": "[parameters('containerMaxReplicas')]" + }, + "daprEnabled": { + "value": "[parameters('daprEnabled')]" + }, + "daprAppId": { + "value": "[parameters('daprAppId')]" + }, + "daprAppProtocol": { + "value": "[parameters('daprAppProtocol')]" + }, + "secrets": { + "value": "[parameters('secrets')]" + }, + "external": { + "value": "[parameters('external')]" + }, + "env": { + "value": "[parameters('env')]" + }, + "imageName": "[if(not(empty(parameters('imageName'))), createObject('value', parameters('imageName')), if(parameters('exists'), createObject('value', reference('existingApp').template.containers[0].image), createObject('value', '')))]", + "targetPort": { + "value": "[parameters('targetPort')]" + }, + "serviceBinds": { + "value": "[parameters('serviceBinds')]" + }, + "principalId": "[if(and(not(empty(parameters('identityName'))), not(empty(parameters('containerRegistryName')))), createObject('value', parameters('identityPrincipalId')), createObject('value', ''))]", + "userAssignedIdentityResourceId": "[if(and(not(empty(parameters('identityName'))), not(empty(parameters('containerRegistryName')))), createObject('value', parameters('userAssignedIdentityResourceId')), createObject('value', ''))]", + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "1832494856594008897" + }, + "name": "Azd ACR Linked Container App", + "description": "Creates a container app in an Azure Container App environment.\n\n**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "environmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "allowedOrigins": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Allowed origins." + } + }, + "containerAppsEnvironmentName": { + "type": "string", + "metadata": { + "description": "Required. Name of the environment for container apps." + } + }, + "containerCpuCoreCount": { + "type": "string", + "defaultValue": "0.5", + "metadata": { + "description": "Optional. CPU cores allocated to a single container instance, e.g., 0.5." + } + }, + "containerMaxReplicas": { + "type": "int", + "defaultValue": 10, + "minValue": 1, + "metadata": { + "description": "Optional. The maximum number of replicas to run. Must be at least 1." + } + }, + "containerMemory": { + "type": "string", + "defaultValue": "1.0Gi", + "metadata": { + "description": "Optional. Memory allocated to a single container instance, e.g., 1Gi." + } + }, + "containerMinReplicas": { + "type": "int", + "defaultValue": 2, + "metadata": { + "description": "Optional. The minimum number of replicas to run. Must be at least 2." + } + }, + "containerName": { + "type": "string", + "defaultValue": "main", + "metadata": { + "description": "Optional. The name of the container." + } + }, + "containerRegistryName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container registry." + } + }, + "containerRegistryHostSuffix": { + "type": "string", + "defaultValue": "azurecr.io", + "metadata": { + "description": "Optional. Hostname suffix for container registry. Set when deploying to sovereign clouds." + } + }, + "daprAppProtocol": { + "type": "string", + "defaultValue": "http", + "allowedValues": [ + "http", + "grpc" + ], + "metadata": { + "description": "Optional. The protocol used by Dapr to connect to the app, e.g., http or grpc." + } + }, + "daprAppId": { + "type": "string", + "defaultValue": "[parameters('containerName')]", + "metadata": { + "description": "Optional. The Dapr app ID." + } + }, + "daprEnabled": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Enable Dapr." + } + }, + "env": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The environment variables for the container." + } + }, + "external": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if the resource ingress is exposed externally." + } + }, + "identityName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the user-assigned identity." + } + }, + "identityType": { + "type": "string", + "defaultValue": "None", + "allowedValues": [ + "None", + "SystemAssigned", + "UserAssigned" + ], + "metadata": { + "description": "Optional. The type of identity for the resource." + } + }, + "imageName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container image." + } + }, + "ingressEnabled": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Specifies if Ingress is enabled for the container app." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Rules to restrict incoming IP address." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "revisionMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "secrets": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The secrets required for the container." + } + }, + "serviceBinds": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. The service binds associated with the container." + } + }, + "serviceType": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name of the container apps add-on to use. e.g. redis." + } + }, + "targetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. The target port for the container." + } + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "principalId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The principal ID of the principal to assign the role to." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The resource id of the user-assigned identity." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "usePrivateRegistry": "[and(not(empty(parameters('identityName'))), not(empty(parameters('containerRegistryName'))))]", + "normalizedIdentityType": "[if(not(empty(parameters('identityName'))), 'UserAssigned', parameters('identityType'))]" + }, + "resources": { + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.azd-acrcontainerapp.{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" + } + } + } + } + }, + "containerAppsEnvironment": { + "existing": true, + "type": "Microsoft.App/managedEnvironments", + "apiVersion": "2023-05-01", + "name": "[parameters('containerAppsEnvironmentName')]" + }, + "containerApp": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-container-app', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[parameters('name')]" + }, + "location": { + "value": "[parameters('location')]" + }, + "tags": { + "value": "[parameters('tags')]" + }, + "managedIdentities": "[if(and(not(empty(parameters('identityName'))), equals(variables('normalizedIdentityType'), 'UserAssigned')), createObject('value', createObject('userAssignedResourceIds', createArray(parameters('userAssignedIdentityResourceId')))), createObject('value', createObject('systemAssigned', equals(variables('normalizedIdentityType'), 'SystemAssigned'))))]", + "environmentResourceId": { + "value": "[resourceId('Microsoft.App/managedEnvironments', parameters('containerAppsEnvironmentName'))]" + }, + "activeRevisionsMode": { + "value": "[parameters('revisionMode')]" + }, + "disableIngress": { + "value": "[not(parameters('ingressEnabled'))]" + }, + "ingressExternal": { + "value": "[parameters('external')]" + }, + "ingressTargetPort": { + "value": "[parameters('targetPort')]" + }, + "ingressTransport": { + "value": "[parameters('ingressTransport')]" + }, + "ipSecurityRestrictions": { + "value": "[parameters('ipSecurityRestrictions')]" + }, + "ingressAllowInsecure": { + "value": "[parameters('ingressAllowInsecure')]" + }, + "corsPolicy": { + "value": { + "allowedOrigins": "[union(createArray('https://portal.azure.com', 'https://ms.portal.azure.com'), parameters('allowedOrigins'))]" + } + }, + "dapr": "[if(parameters('daprEnabled'), createObject('value', createObject('enabled', true(), 'appId', parameters('daprAppId'), 'appProtocol', parameters('daprAppProtocol'), 'appPort', if(parameters('ingressEnabled'), parameters('targetPort'), 0))), createObject('value', createObject('enabled', false())))]", + "secrets": { + "value": "[parameters('secrets')]" + }, + "includeAddOns": { + "value": "[parameters('includeAddOns')]" + }, + "service": { + "value": { + "type": "[parameters('serviceType')]" + } + }, + "registries": "[if(variables('usePrivateRegistry'), createObject('value', createArray(createObject('server', format('{0}.{1}', parameters('containerRegistryName'), parameters('containerRegistryHostSuffix')), 'identity', parameters('userAssignedIdentityResourceId')))), createObject('value', createArray()))]", + "serviceBinds": { + "value": "[parameters('serviceBinds')]" + }, + "containers": { + "value": [ + { + "image": "[if(not(empty(parameters('imageName'))), parameters('imageName'), 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest')]", + "name": "[parameters('containerName')]", + "env": "[parameters('env')]", + "resources": { + "cpu": "[json(parameters('containerCpuCoreCount'))]", + "memory": "[parameters('containerMemory')]" + } + } + ] + }, + "scaleMaxReplicas": { + "value": "[parameters('containerMaxReplicas')]" + }, + "scaleMinReplicas": { + "value": "[parameters('containerMinReplicas')]" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.29.47.4906", + "templateHash": "9894768173968934379" + }, + "name": "Container Apps", + "description": "This module deploys a Container App.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "managedIdentitiesType": { + "type": "object", + "properties": { + "systemAssigned": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enables system assigned managed identity on the resource." + } + }, + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource." + } + } + }, + "nullable": true + }, + "lockType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Specify the name of lock." + } + }, + "kind": { + "type": "string", + "allowedValues": [ + "CanNotDelete", + "None", + "ReadOnly" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + } + }, + "nullable": true + }, + "roleAssignmentType": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name (as GUID) of the role assignment. If not provided, a GUID will be generated." + } + }, + "roleDefinitionIdOrName": { + "type": "string", + "metadata": { + "description": "Required. The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User" + ], + "nullable": true, + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The description of the role assignment." + } + }, + "condition": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase \"foo_storage_container\"." + } + }, + "conditionVersion": { + "type": "string", + "allowedValues": [ + "2.0" + ], + "nullable": true, + "metadata": { + "description": "Optional. Version of the condition." + } + }, + "delegatedManagedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The Resource Id of the delegated managed identity resource." + } + } + } + }, + "nullable": true + }, + "container": { + "type": "object", + "properties": { + "args": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container start command arguments." + } + }, + "command": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container start command." + } + }, + "env": { + "type": "array", + "items": { + "$ref": "#/definitions/environmentVar" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container environment variables." + } + }, + "image": { + "type": "string", + "metadata": { + "description": "Required. Container image tag." + } + }, + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Custom container name." + } + }, + "probes": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbe" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of probes for the container." + } + }, + "resources": { + "type": "object", + "metadata": { + "description": "Required. Container resource requirements." + } + }, + "volumeMounts": { + "type": "array", + "items": { + "$ref": "#/definitions/volumeMount" + }, + "nullable": true, + "metadata": { + "description": "Optional. Container volume mounts." + } + } + } + }, + "ingressPortMapping": { + "type": "object", + "properties": { + "exposedPort": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the exposed port for the target port. If not specified, it defaults to target port." + } + }, + "external": { + "type": "bool", + "metadata": { + "description": "Required. Specifies whether the app port is accessible outside of the environment." + } + }, + "targetPort": { + "type": "int", + "metadata": { + "description": "Required. Specifies the port the container listens on." + } + } + } + }, + "serviceBind": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the service." + } + }, + "serviceId": { + "type": "string", + "metadata": { + "description": "Required. The service ID." + } + } + } + }, + "environmentVar": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Environment variable name." + } + }, + "secretRef": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the Container App secret from which to pull the environment variable value." + } + }, + "value": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Non-secret environment variable value." + } + } + } + }, + "containerAppProbe": { + "type": "object", + "properties": { + "failureThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive failures for the probe to be considered failed after having succeeded. Defaults to 3." + } + }, + "httpGet": { + "$ref": "#/definitions/containerAppProbeHttpGet", + "nullable": true, + "metadata": { + "description": "Optional. HTTPGet specifies the http request to perform." + } + }, + "initialDelaySeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 60, + "metadata": { + "description": "Optional. Number of seconds after the container has started before liveness probes are initiated." + } + }, + "periodSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. How often (in seconds) to perform the probe. Default to 10 seconds." + } + }, + "successThreshold": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 10, + "metadata": { + "description": "Optional. Minimum consecutive successes for the probe to be considered successful after having failed. Defaults to 1. Must be 1 for liveness and startup." + } + }, + "tcpSocket": { + "$ref": "#/definitions/containerAppProbeTcpSocket", + "nullable": true, + "metadata": { + "description": "Optional. TCPSocket specifies an action involving a TCP port. TCP hooks not yet supported." + } + }, + "terminationGracePeriodSeconds": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Optional duration in seconds the pod needs to terminate gracefully upon probe failure. The grace period is the duration in seconds after the processes running in the pod are sent a termination signal and the time when the processes are forcibly halted with a kill signal. Set this value longer than the expected cleanup time for your process. If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this value overrides the value provided by the pod spec. Value must be non-negative integer. The value zero indicates stop immediately via the kill signal (no opportunity to shut down). This is an alpha field and requires enabling ProbeTerminationGracePeriod feature gate. Maximum value is 3600 seconds (1 hour)." + } + }, + "timeoutSeconds": { + "type": "int", + "nullable": true, + "minValue": 1, + "maxValue": 240, + "metadata": { + "description": "Optional. Number of seconds after which the probe times out. Defaults to 1 second." + } + }, + "type": { + "type": "string", + "allowedValues": [ + "Liveness", + "Readiness", + "Startup" + ], + "nullable": true, + "metadata": { + "description": "Optional. The type of probe." + } + } + } + }, + "corsPolicyType": { + "type": "object", + "properties": { + "allowCredentials": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Switch to determine whether the resource allows credentials." + } + }, + "allowedHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-headers header." + } + }, + "allowedMethods": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-methods header." + } + }, + "allowedOrigins": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-allow-origins header." + } + }, + "exposeHeaders": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-expose-headers header." + } + }, + "maxAge": { + "type": "int", + "nullable": true, + "metadata": { + "description": "Optional. Specifies the content for the access-control-max-age header." + } + } + }, + "nullable": true + }, + "containerAppProbeHttpGet": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to. Defaults to the pod IP." + } + }, + "httpHeaders": { + "type": "array", + "items": { + "$ref": "#/definitions/containerAppProbeHttpGetHeadersItem" + }, + "nullable": true, + "metadata": { + "description": "Optional. HTTP headers to set in the request." + } + }, + "path": { + "type": "string", + "metadata": { + "description": "Required. Path to access on the HTTP server." + } + }, + "port": { + "type": "int", + "metadata": { + "description": "Required. Name or number of the port to access on the container." + } + }, + "scheme": { + "type": "string", + "allowedValues": [ + "HTTP", + "HTTPS" + ], + "nullable": true, + "metadata": { + "description": "Optional. Scheme to use for connecting to the host. Defaults to HTTP." + } + } + } + }, + "containerAppProbeHttpGetHeadersItem": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the header." + } + }, + "value": { + "type": "string", + "metadata": { + "description": "Required. Value of the header." + } + } + } + }, + "containerAppProbeTcpSocket": { + "type": "object", + "properties": { + "host": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Host name to connect to, defaults to the pod IP." + } + }, + "port": { + "type": "int", + "minValue": 1, + "maxValue": 65535, + "metadata": { + "description": "Required. Number of the port to access on the container. Name must be an IANA_SVC_NAME." + } + } + } + }, + "volumeMount": { + "type": "object", + "properties": { + "mountPath": { + "type": "string", + "metadata": { + "description": "Required. Path within the container at which the volume should be mounted.Must not contain ':'." + } + }, + "subPath": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root)." + } + }, + "volumeName": { + "type": "string", + "metadata": { + "description": "Required. This must match the Name of a Volume." + } + } + } + } + }, + "parameters": { + "name": { + "type": "string", + "metadata": { + "description": "Required. Name of the Container App." + } + }, + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all Resources." + } + }, + "disableIngress": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Bool to disable all ingress traffic for the container app." + } + }, + "ingressExternal": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if the App exposes an external HTTP endpoint." + } + }, + "clientCertificateMode": { + "type": "string", + "defaultValue": "ignore", + "allowedValues": [ + "accept", + "ignore", + "require" + ], + "metadata": { + "description": "Optional. Client certificate mode for mTLS." + } + }, + "corsPolicy": { + "$ref": "#/definitions/corsPolicyType", + "metadata": { + "description": "Optional. Object userd to configure CORS policy." + } + }, + "stickySessionsAffinity": { + "type": "string", + "defaultValue": "none", + "allowedValues": [ + "none", + "sticky" + ], + "metadata": { + "description": "Optional. Bool indicating if the Container App should enable session affinity." + } + }, + "ingressTransport": { + "type": "string", + "defaultValue": "auto", + "allowedValues": [ + "auto", + "http", + "http2", + "tcp" + ], + "metadata": { + "description": "Optional. Ingress transport protocol." + } + }, + "service": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dev ContainerApp service type." + } + }, + "includeAddOns": { + "type": "bool", + "defaultValue": false, + "metadata": { + "description": "Optional. Toggle to include the service configuration." + } + }, + "additionalPortMappings": { + "type": "array", + "items": { + "$ref": "#/definitions/ingressPortMapping" + }, + "nullable": true, + "metadata": { + "description": "Optional. Settings to expose additional ports on container app." + } + }, + "ingressAllowInsecure": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Bool indicating if HTTP connections to is allowed. If set to false HTTP connections are automatically redirected to HTTPS connections." + } + }, + "ingressTargetPort": { + "type": "int", + "defaultValue": 80, + "metadata": { + "description": "Optional. Target Port in containers for traffic from ingress." + } + }, + "scaleMaxReplicas": { + "type": "int", + "defaultValue": 10, + "metadata": { + "description": "Optional. Maximum number of container replicas. Defaults to 10 if not set." + } + }, + "scaleMinReplicas": { + "type": "int", + "defaultValue": 3, + "metadata": { + "description": "Optional. Minimum number of container replicas. Defaults to 3 if not set." + } + }, + "scaleRules": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Scaling rules." + } + }, + "serviceBinds": { + "type": "array", + "items": { + "$ref": "#/definitions/serviceBind" + }, + "nullable": true, + "metadata": { + "description": "Optional. List of container app services bound to the app." + } + }, + "activeRevisionsMode": { + "type": "string", + "defaultValue": "Single", + "allowedValues": [ + "Multiple", + "Single" + ], + "metadata": { + "description": "Optional. Controls how active revisions are handled for the Container app." + } + }, + "environmentResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of environment." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "registries": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Collection of private container registry credentials for containers used by the Container app." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentitiesType", + "metadata": { + "description": "Optional. The managed identity definition for this resource." + } + }, + "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." + } + }, + "customDomains": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Custom domain bindings for Container App hostnames." + } + }, + "exposedPort": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Exposed Port in containers for TCP traffic from ingress." + } + }, + "ipSecurityRestrictions": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. Rules to restrict incoming IP address." + } + }, + "trafficLabel": { + "type": "string", + "defaultValue": "label-1", + "metadata": { + "description": "Optional. Associates a traffic label with a revision. Label name should be consist of lower case alphanumeric characters or dashes." + } + }, + "trafficLatestRevision": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Indicates that the traffic weight belongs to a latest stable revision." + } + }, + "trafficRevisionName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Name of a revision." + } + }, + "trafficWeight": { + "type": "int", + "defaultValue": 100, + "metadata": { + "description": "Optional. Traffic weight assigned to a revision." + } + }, + "dapr": { + "type": "object", + "defaultValue": {}, + "metadata": { + "description": "Optional. Dapr configuration for the Container App." + } + }, + "maxInactiveRevisions": { + "type": "int", + "defaultValue": 0, + "metadata": { + "description": "Optional. Max inactive revisions a Container App can have." + } + }, + "containers": { + "type": "array", + "items": { + "$ref": "#/definitions/container" + }, + "metadata": { + "description": "Required. List of container definitions for the Container App." + } + }, + "initContainersTemplate": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of specialized containers that run before app containers." + } + }, + "secrets": { + "type": "secureObject", + "defaultValue": {}, + "metadata": { + "description": "Optional. The secrets of the Container App." + } + }, + "revisionSuffix": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. User friendly suffix that is appended to the revision name." + } + }, + "volumes": { + "type": "array", + "defaultValue": [], + "metadata": { + "description": "Optional. List of volume definitions for the Container App." + } + }, + "workloadProfileName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. Workload profile name to pin for container app execution." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "secretList": "[if(not(empty(parameters('secrets'))), parameters('secrets').secureList, createArray())]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(coalesce(tryGet(parameters('managedIdentities'), 'systemAssigned'), false()), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'SystemAssigned,UserAssigned', 'SystemAssigned'), if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None')), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "ContainerApp Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'ad2dd5fb-cd4b-4fd4-a9b6-4fed3630980b')]", + "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": "2024-03-01", + "name": "[format('46d3xbcp.res.app-containerapp.{0}.{1}', replace('0.10.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" + } + } + } + } + }, + "containerApp": { + "type": "Microsoft.App/containerApps", + "apiVersion": "2024-03-01", + "name": "[parameters('name')]", + "tags": "[parameters('tags')]", + "location": "[parameters('location')]", + "identity": "[variables('identity')]", + "properties": { + "environmentId": "[parameters('environmentResourceId')]", + "configuration": { + "activeRevisionsMode": "[parameters('activeRevisionsMode')]", + "dapr": "[if(not(empty(parameters('dapr'))), parameters('dapr'), null())]", + "ingress": "[if(parameters('disableIngress'), null(), createObject('additionalPortMappings', parameters('additionalPortMappings'), 'allowInsecure', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('ingressAllowInsecure'), false()), 'customDomains', if(not(empty(parameters('customDomains'))), parameters('customDomains'), null()), 'corsPolicy', if(and(not(equals(parameters('corsPolicy'), null())), not(equals(parameters('ingressTransport'), 'tcp'))), createObject('allowCredentials', coalesce(tryGet(parameters('corsPolicy'), 'allowCredentials'), false()), 'allowedHeaders', coalesce(tryGet(parameters('corsPolicy'), 'allowedHeaders'), createArray()), 'allowedMethods', coalesce(tryGet(parameters('corsPolicy'), 'allowedMethods'), createArray()), 'allowedOrigins', coalesce(tryGet(parameters('corsPolicy'), 'allowedOrigins'), createArray()), 'exposeHeaders', coalesce(tryGet(parameters('corsPolicy'), 'exposeHeaders'), createArray()), 'maxAge', tryGet(parameters('corsPolicy'), 'maxAge')), null()), 'clientCertificateMode', if(not(equals(parameters('ingressTransport'), 'tcp')), parameters('clientCertificateMode'), null()), 'exposedPort', parameters('exposedPort'), 'external', parameters('ingressExternal'), 'ipSecurityRestrictions', if(not(empty(parameters('ipSecurityRestrictions'))), parameters('ipSecurityRestrictions'), null()), 'targetPort', parameters('ingressTargetPort'), 'stickySessions', createObject('affinity', parameters('stickySessionsAffinity')), 'traffic', if(not(equals(parameters('ingressTransport'), 'tcp')), createArray(createObject('label', parameters('trafficLabel'), 'latestRevision', parameters('trafficLatestRevision'), 'revisionName', parameters('trafficRevisionName'), 'weight', parameters('trafficWeight'))), null()), 'transport', parameters('ingressTransport')))]", + "service": "[if(and(parameters('includeAddOns'), not(empty(parameters('service')))), parameters('service'), null())]", + "maxInactiveRevisions": "[parameters('maxInactiveRevisions')]", + "registries": "[if(not(empty(parameters('registries'))), parameters('registries'), null())]", + "secrets": "[variables('secretList')]" + }, + "template": { + "containers": "[parameters('containers')]", + "initContainers": "[if(not(empty(parameters('initContainersTemplate'))), parameters('initContainersTemplate'), null())]", + "revisionSuffix": "[parameters('revisionSuffix')]", + "scale": { + "maxReplicas": "[parameters('scaleMaxReplicas')]", + "minReplicas": "[parameters('scaleMinReplicas')]", + "rules": "[if(not(empty(parameters('scaleRules'))), parameters('scaleRules'), null())]" + }, + "serviceBinds": "[if(and(parameters('includeAddOns'), not(empty(parameters('serviceBinds')))), parameters('serviceBinds'), null())]", + "volumes": "[if(not(empty(parameters('volumes'))), parameters('volumes'), null())]" + }, + "workloadProfileName": "[parameters('workloadProfileName')]" + } + }, + "containerApp_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.App/containerApps/{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": [ + "containerApp" + ] + }, + "containerApp_roleAssignments": { + "copy": { + "name": "containerApp_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.App/containerApps/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.App/containerApps', parameters('name')), coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId, coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId))]", + "properties": { + "roleDefinitionId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].roleDefinitionId]", + "principalId": "[coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()].principalId]", + "description": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'description')]", + "principalType": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'principalType')]", + "condition": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition')]", + "conditionVersion": "[if(not(empty(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'condition'))), coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'conditionVersion'), '2.0'), null())]", + "delegatedManagedIdentityResourceId": "[tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'delegatedManagedIdentityResourceId')]" + }, + "dependsOn": [ + "containerApp" + ] + } + }, + "outputs": { + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[resourceId('Microsoft.App/containerApps', parameters('name'))]" + }, + "fqdn": { + "type": "string", + "metadata": { + "description": "The configuration of ingress fqdn." + }, + "value": "[if(parameters('disableIngress'), 'IngressDisabled', reference('containerApp').configuration.ingress.fqdn)]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[parameters('name')]" + }, + "systemAssignedMIPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the system assigned identity." + }, + "value": "[coalesce(tryGet(tryGet(reference('containerApp', '2024-03-01', 'full'), 'identity'), 'principalId'), '')]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('containerApp', '2024-03-01', 'full').location]" + } + } + } + }, + "dependsOn": [ + "containerAppsEnvironment", + "containerRegistryAccess" + ] + }, + "containerRegistryAccess": { + "condition": "[variables('usePrivateRegistry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-registry-access', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "containerRegistryName": { + "value": "[parameters('containerRegistryName')]" + }, + "principalId": "[if(variables('usePrivateRegistry'), createObject('value', parameters('principalId')), createObject('value', ''))]", + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.30.23.60470", + "templateHash": "11140098273900072819" + }, + "name": "ACR Pull permissions", + "description": "Assigns ACR Pull permissions to access an Azure Container Registry.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "containerRegistryName": { + "type": "string", + "metadata": { + "description": "Required. The name of the container registry." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The principal ID of the principal (user/group/identity) to assign the role to." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "acrPullRole": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7f951dda-4ed3-4680-a7ca-43fe172d538d')]" + }, + "resources": [ + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "acrpullrole-deployment", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "principalId": { + "value": "[parameters('principalId')]" + }, + "resourceId": { + "value": "[resourceId('Microsoft.ContainerRegistry/registries', parameters('containerRegistryName'))]" + }, + "roleDefinitionId": { + "value": "[variables('acrPullRole')]" + }, + "principalType": { + "value": "ServicePrincipal" + }, + "enableTelemetry": { + "value": "[parameters('enableTelemetry')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.28.1.47646", + "templateHash": "1847432691715853168" + }, + "name": "Resource-scoped role assignment", + "description": "This module deploys a Role Assignment for a specific resource.", + "owner": "Azure/module-maintainers" + }, + "parameters": { + "resourceId": { + "type": "string", + "metadata": { + "description": "Required. The scope for the role assignment, fully qualified resourceId." + } + }, + "name": { + "type": "string", + "defaultValue": "[guid(parameters('resourceId'), parameters('principalId'), if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId'))))]", + "metadata": { + "description": "Optional. The unique guid name for the role assignment." + } + }, + "roleDefinitionId": { + "type": "string", + "metadata": { + "description": "Required. The role definition ID for the role assignment." + } + }, + "roleName": { + "type": "string", + "defaultValue": "", + "metadata": { + "description": "Optional. The name for the role, used for logging." + } + }, + "principalId": { + "type": "string", + "metadata": { + "description": "Required. The Principal or Object ID of the Security Principal (User, Group, Service Principal, Managed Identity)." + } + }, + "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 role assignment." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "$fxv#0": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "scope": { + "type": "string" + }, + "name": { + "type": "string" + }, + "roleDefinitionId": { + "type": "string" + }, + "principalId": { + "type": "string" + }, + "principalType": { + "type": "string", + "allowedValues": [ + "Device", + "ForeignGroup", + "Group", + "ServicePrincipal", + "User", + "" + ], + "defaultValue": "", + "metadata": { + "description": "Optional. The principal type of the assigned principal ID." + } + }, + "description": { + "type": "string" + } + }, + "resources": [ + { + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[[parameters('scope')]", + "name": "[[parameters('name')]", + "properties": { + "roleDefinitionId": "[[parameters('roleDefinitionId')]", + "principalId": "[[parameters('principalId')]", + "principalType": "[[parameters('principalType')]", + "description": "[[parameters('description')]" + } + } + ], + "outputs": { + "roleAssignmentId": { + "type": "string", + "value": "[[extensionResourceId(parameters('scope'), 'Microsoft.Authorization/roleAssignments', parameters('name'))]" + } + } + } + }, + "resources": [ + { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.ptn.authorization-resourceroleassignment.{0}.{1}', replace('0.1.1', '.', '-'), substring(uniqueString(deployment().name), 0, 4))]", + "properties": { + "mode": "Incremental", + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "contentVersion": "1.0.0.0", + "resources": [], + "outputs": { + "telemetry": { + "type": "String", + "value": "For more information, see https://aka.ms/avm/TelemetryInfo" + } + } + } + } + }, + { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2023-07-01", + "name": "[format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))]", + "properties": { + "mode": "Incremental", + "expressionEvaluationOptions": { + "scope": "Outer" + }, + "template": "[variables('$fxv#0')]", + "parameters": { + "scope": { + "value": "[parameters('resourceId')]" + }, + "name": { + "value": "[parameters('name')]" + }, + "roleDefinitionId": { + "value": "[if(contains(parameters('roleDefinitionId'), '/providers/Microsoft.Authorization/roleDefinitions/'), parameters('roleDefinitionId'), subscriptionResourceId('Microsoft.Authorization/roleDefinitions', parameters('roleDefinitionId')))]" + }, + "principalId": { + "value": "[parameters('principalId')]" + }, + "principalType": { + "value": "[parameters('principalType')]" + }, + "description": { + "value": "[parameters('description')]" + } + } + } + } + ], + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The GUID of the Role Assignment." + }, + "value": "[parameters('name')]" + }, + "roleName": { + "type": "string", + "metadata": { + "description": "The name for the role, used for logging." + }, + "value": "[parameters('roleName')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Role Assignment." + }, + "value": "[reference(resourceId('Microsoft.Resources/deployments', format('{0}-ResourceRoleAssignment', guid(parameters('resourceId'), parameters('principalId'), parameters('roleDefinitionId')))), '2023-07-01').outputs.roleAssignmentId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the role assignment was applied at." + }, + "value": "[resourceGroup().name]" + } + } + } + } + } + ] + } + } + } + }, + "outputs": { + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Managed Environment." + }, + "value": "[reference('containerAppsEnvironment').defaultDomain]" + }, + "identityPrincipalId": { + "type": "string", + "metadata": { + "description": "The principal ID of the identity." + }, + "value": "[if(equals(variables('normalizedIdentityType'), 'None'), '', if(empty(parameters('identityName')), reference('containerApp').outputs.systemAssignedMIPrincipalId.value, parameters('principalId')))]" + }, + "imageName": { + "type": "string", + "metadata": { + "description": "The name of the container image." + }, + "value": "[parameters('imageName')]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[reference('containerApp').outputs.name.value]" + }, + "serviceBind": { + "type": "object", + "metadata": { + "description": "The service binds associated with the container." + }, + "value": "[if(not(empty(parameters('serviceType'))), createObject('serviceId', reference('containerApp').outputs.resourceId.value, 'name', reference('containerApp').outputs.name.value), createObject())]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The uri of the Container App." + }, + "value": "[if(parameters('ingressEnabled'), format('https://{0}', reference('containerApp').outputs.fqdn.value), '')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[reference('containerApp').outputs.resourceId.value]" + } + } + } + }, + "dependsOn": [ + "existingApp" + ] + } + }, + "outputs": { + "defaultDomain": { + "type": "string", + "metadata": { + "description": "The Default domain of the Container App." + }, + "value": "[reference('app').outputs.defaultDomain.value]" + }, + "imageName": { + "type": "string", + "metadata": { + "description": "The name of the container image." + }, + "value": "[reference('app').outputs.imageName.value]" + }, + "name": { + "type": "string", + "metadata": { + "description": "The name of the Container App." + }, + "value": "[reference('app').outputs.name.value]" + }, + "uri": { + "type": "string", + "metadata": { + "description": "The uri of the Container App." + }, + "value": "[reference('app').outputs.uri.value]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Container App." + }, + "value": "[reference('app').outputs.resourceId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Container App was deployed into." + }, + "value": "[resourceGroup().name]" + } + } +} \ No newline at end of file diff --git a/avm/ptn/azd/container-app-upsert/tests/e2e/defaults/dependencies.bicep b/avm/ptn/azd/container-app-upsert/tests/e2e/defaults/dependencies.bicep new file mode 100644 index 0000000000..6c93d0689b --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/tests/e2e/defaults/dependencies.bicep @@ -0,0 +1,14 @@ +@description('Required. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Environment to create.') +param managedEnvironmentName string + +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: managedEnvironmentName + location: location + properties: {} +} + +@description('The name of the Container Apps environment.') +output containerAppsEnvironmentName string = managedEnvironment.name diff --git a/avm/ptn/azd/container-app-upsert/tests/e2e/defaults/main.test.bicep b/avm/ptn/azd/container-app-upsert/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..e991a50a79 --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,58 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-azd-containerappupsert-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'acaumin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedEnvironmentName: 'dep-${namePrefix}-me-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + containerAppsEnvironmentName: nestedDependencies.outputs.containerAppsEnvironmentName + location: resourceLocation + } + } +] diff --git a/avm/ptn/azd/container-app-upsert/tests/e2e/max/dependencies.bicep b/avm/ptn/azd/container-app-upsert/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..a1bb685580 --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/tests/e2e/max/dependencies.bicep @@ -0,0 +1,120 @@ +@description('Required. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Environment to create.') +param managedEnvironmentName string + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Key Vault referenced by the Container Apps.') +param keyVaultName string + +@description('Required. The secret name of the Key Vault referenced by the Container Apps.') +param keyVaultSecretName string + +@description('Optional. Key vault stored secret to pass into environment variables. The value is a GUID.') +@secure() +param myCustomKeyVaultSecret string = newGuid() + +@description('Required. The name of the Container App.') +param containerAppName string + +@description('Required. The name of the Container Registry.') +param containerRegistryName string + +resource managedEnvironment 'Microsoft.App/managedEnvironments@2023-05-01' = { + name: managedEnvironmentName + location: location + properties: {} +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2023-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: subscription().tenantId + publicNetworkAccess: 'Enabled' + enableRbacAuthorization: true + } +} + +resource keyVaultSecret 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = { + parent: keyVault + name: keyVaultSecretName + properties: { + value: myCustomKeyVaultSecret + } +} + +@description('The the built-in Key Vault Secret User role definition.') +resource roleDefinitionKeyVault 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + scope: subscription() + name: '4633458b-17de-408a-b874-0445c86b69e6' +} + +resource roleAssignmentKeyVault 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(resourceGroup().id, managedIdentity.id) + scope: keyVault + properties: { + roleDefinitionId: roleDefinitionKeyVault.id + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +module containerApp 'br/public:avm/res/app/container-app:0.9.0' = { + name: containerAppName + params: { + name: containerAppName + containers: [ + { + name: 'simple-hello-world-container' + image: 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest' + resources: { + // workaround as 'float' values are not supported in Bicep, yet the resource providers expects them. Related issue: https://github.com/Azure/bicep/issues/1386 + cpu: json('0.25') + memory: '0.5Gi' + } + } + ] + environmentResourceId: managedEnvironment.id + } +} + +module containerRegistry 'br/public:avm/res/container-registry/registry:0.5.1' = { + name: containerRegistryName + params: { + name: containerRegistryName + } +} + +@description('The name of the Container Apps environment.') +output containerAppsEnvironmentName string = managedEnvironment.name + +@description('The resource id of the created managed identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The name of the created managed identity.') +output managedIdentityName string = managedIdentity.name + +@description('The principalId of the created managed identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The key vault secret URI.') +output keyVaultSecretURI string = keyVaultSecret.properties.secretUri + +@description('The name of the Container Apps environment.') +output existingcontainerAppName string = containerApp.outputs.name + +@description('The Name of the Azure container registry.') +output containerRegistryName string = containerRegistry.outputs.name diff --git a/avm/ptn/azd/container-app-upsert/tests/e2e/max/main.test.bicep b/avm/ptn/azd/container-app-upsert/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..bc27f38b58 --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/tests/e2e/max/main.test.bicep @@ -0,0 +1,101 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-azd-containerappupsert-${serviceShort}-rg' + +@description('Optional. The location to deploy resources to.') +param resourceLocation string = deployment().location + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'acaumax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +@description('Optional. Container app stored secret to pass into environment variables. The value is a GUID.') +@secure() +param myCustomContainerAppSecret string = newGuid() + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedEnvironmentName: 'dep-${namePrefix}-me-${serviceShort}' + managedIdentityName: 'dep-${namePrefix}-mi-${serviceShort}' + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + keyVaultSecretName: 'dep-${namePrefix}-kv-secret-${serviceShort}' + containerAppName: 'dep-${namePrefix}-ca-${serviceShort}' + containerRegistryName: 'dep${namePrefix}cr${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: nestedDependencies.outputs.existingcontainerAppName + tags: { + 'hidden-title': 'This is visible in the resource name' + Env: 'test' + } + containerAppsEnvironmentName: nestedDependencies.outputs.containerAppsEnvironmentName + location: resourceLocation + identityType: 'UserAssigned' + identityName: nestedDependencies.outputs.managedIdentityName + containerRegistryName: nestedDependencies.outputs.containerRegistryName + identityPrincipalId: nestedDependencies.outputs.managedIdentityPrincipalId + userAssignedIdentityResourceId: nestedDependencies.outputs.managedIdentityResourceId + daprEnabled: true + secrets: { + secureList: [ + { + name: 'containerappstoredsecret' + value: myCustomContainerAppSecret + } + { + name: 'keyvaultstoredsecret' + keyVaultUrl: nestedDependencies.outputs.keyVaultSecretURI + identity: nestedDependencies.outputs.managedIdentityResourceId + } + ] + } + env: [ + { + name: 'ContainerAppStoredSecretName' + secretRef: 'containerappstoredsecret' + } + { + name: 'ContainerAppKeyVaultStoredSecretName' + secretRef: 'keyvaultstoredsecret' + } + ] + exists: true + } + } +] diff --git a/avm/ptn/azd/container-app-upsert/version.json b/avm/ptn/azd/container-app-upsert/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/ptn/azd/container-app-upsert/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +} From cb96bfc045e3981943e83e1985cf1b3428d46ead Mon Sep 17 00:00:00 2001 From: AlexanderSehr Date: Sat, 12 Oct 2024 11:33:42 +0200 Subject: [PATCH 17/17] Updated PE implementation --- avm/res/cognitive-services/account/README.md | 257 +++++++++++++----- avm/res/cognitive-services/account/main.bicep | 35 ++- avm/res/cognitive-services/account/main.json | 214 +++++++++++---- .../main.test.bicep | 15 +- .../account/tests/e2e/max/main.test.bicep | 20 +- .../tests/e2e/openai-private/main.test.bicep | 11 +- .../account/tests/e2e/speech/main.test.bicep | 10 +- .../tests/e2e/waf-aligned/main.test.bicep | 10 +- .../cognitive-services/account/version.json | 2 +- 9 files changed, 428 insertions(+), 146 deletions(-) diff --git a/avm/res/cognitive-services/account/README.md b/avm/res/cognitive-services/account/README.md index a2c4698c2e..c4316e2e52 100644 --- a/avm/res/cognitive-services/account/README.md +++ b/avm/res/cognitive-services/account/README.md @@ -78,10 +78,16 @@ module account 'br/public:avm/res/cognitive-services/account:' = { location: '' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - '' - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -135,10 +141,16 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "privateEndpoints": { "value": [ { - "privateDnsZoneResourceIds": [ - "", - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + }, + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "" } ] @@ -182,10 +194,16 @@ param deployments = [ param location = '' param privateEndpoints = [ { - privateDnsZoneResourceIds: [ - '' - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -553,9 +571,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } } ] - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -564,9 +586,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } } { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -701,9 +727,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } } ], - "privateDnsZoneResourceIds": [ - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "", "tags": { "Environment": "Non-Prod", @@ -712,9 +742,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } }, { - "privateDnsZoneResourceIds": [ - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "" } ] @@ -839,9 +873,13 @@ param privateEndpoints = [ } } ] - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -850,9 +888,13 @@ param privateEndpoints = [ } } { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -922,9 +964,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { location: '' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -978,9 +1024,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "privateEndpoints": { "value": [ { - "privateDnsZoneResourceIds": [ - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "" } ] @@ -1024,9 +1074,13 @@ param deployments = [ param location = '' param privateEndpoints = [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' } ] @@ -1063,9 +1117,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } privateEndpoints: [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -1121,9 +1179,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "privateEndpoints": { "value": [ { - "privateDnsZoneResourceIds": [ - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "", "tags": { "Environment": "Non-Prod", @@ -1171,9 +1233,13 @@ param managedIdentities = { } param privateEndpoints = [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -1456,9 +1522,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { } privateEndpoints: [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -1527,9 +1597,13 @@ module account 'br/public:avm/res/cognitive-services/account:' = { "privateEndpoints": { "value": [ { - "privateDnsZoneResourceIds": [ - "" - ], + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, "subnetResourceId": "", "tags": { "Environment": "Non-Prod", @@ -1586,9 +1660,13 @@ param managedIdentities = { } param privateEndpoints = [ { - privateDnsZoneResourceIds: [ - '' - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } subnetResourceId: '' tags: { Environment: 'Non-Prod' @@ -2150,8 +2228,7 @@ Configuration details for private endpoints. For security reasons, it is recomme | [`lock`](#parameter-privateendpointslock) | object | Specify the type of lock. | | [`manualConnectionRequestMessage`](#parameter-privateendpointsmanualconnectionrequestmessage) | string | A message passed to the owner of the remote resource with the manual connection request. | | [`name`](#parameter-privateendpointsname) | string | The name of the private endpoint. | -| [`privateDnsZoneGroupName`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. | -| [`privateDnsZoneResourceIds`](#parameter-privateendpointsprivatednszoneresourceids) | array | The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. | +| [`privateDnsZoneGroup`](#parameter-privateendpointsprivatednszonegroup) | object | The private DNS zone group to configure for the private endpoint. | | [`privateLinkServiceConnectionName`](#parameter-privateendpointsprivatelinkserviceconnectionname) | string | The name of the private link connection to create. | | [`resourceGroupName`](#parameter-privateendpointsresourcegroupname) | string | Specify if you want to deploy the Private Endpoint into a different resource group than the main resource. | | [`roleAssignments`](#parameter-privateendpointsroleassignments) | array | Array of role assignments to create. | @@ -2335,19 +2412,64 @@ The name of the private endpoint. - Required: No - Type: string -### Parameter: `privateEndpoints.privateDnsZoneGroupName` +### Parameter: `privateEndpoints.privateDnsZoneGroup` -The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided. +The private DNS zone group to configure for the private endpoint. - Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneGroupConfigs`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigs) | array | The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupname) | string | The name of the Private DNS Zone Group. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs` + +The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`privateDnsZoneResourceId`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsprivatednszoneresourceid) | string | The resource id of the private DNS zone. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-privateendpointsprivatednszonegroupprivatednszonegroupconfigsname) | string | The name of the private DNS zone group config. | + +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.privateDnsZoneResourceId` + +The resource id of the private DNS zone. + +- Required: Yes - Type: string -### Parameter: `privateEndpoints.privateDnsZoneResourceIds` +### Parameter: `privateEndpoints.privateDnsZoneGroup.privateDnsZoneGroupConfigs.name` -The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones. +The name of the private DNS zone group config. - Required: No -- Type: array +- Type: string + +### Parameter: `privateEndpoints.privateDnsZoneGroup.name` + +The name of the Private DNS Zone Group. + +- Required: No +- Type: string ### Parameter: `privateEndpoints.privateLinkServiceConnectionName` @@ -2379,7 +2501,7 @@ Array of role assignments to create. - `'Owner'` - `'Private DNS Zone Contributor'` - `'Reader'` - - `'Role Based Access Control Administrator (Preview)'` + - `'Role Based Access Control Administrator'` **Required parameters** @@ -2549,7 +2671,7 @@ Array of role assignments to create. - `'Contributor'` - `'Owner'` - `'Reader'` - - `'Role Based Access Control Administrator (Preview)'` + - `'Role Based Access Control Administrator'` - `'User Access Administrator'` **Required parameters** @@ -2736,6 +2858,7 @@ The storage accounts for this resource. | `exportedSecrets` | | A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name. | | `location` | string | The location the resource was deployed into. | | `name` | string | The name of the cognitive services account. | +| `privateEndpoints` | array | The private endpoints of the congitive services account. | | `resourceGroupName` | string | The resource group the cognitive services account was deployed into. | | `resourceId` | string | The resource ID of the cognitive services account. | | `systemAssignedMIPrincipalId` | string | The principal ID of the system assigned identity. | @@ -2746,7 +2869,7 @@ This section gives you an overview of all local-referenced module files (i.e., o | Reference | Type | | :-- | :-- | -| `br/public:avm/res/network/private-endpoint:0.6.1` | Remote reference | +| `br/public:avm/res/network/private-endpoint:0.8.0` | Remote reference | ## Data Collection diff --git a/avm/res/cognitive-services/account/main.bicep b/avm/res/cognitive-services/account/main.bicep index 8dbadcfb78..e7d426a344 100644 --- a/avm/res/cognitive-services/account/main.bicep +++ b/avm/res/cognitive-services/account/main.bicep @@ -241,7 +241,7 @@ var builtInRoleNames = { Contributor: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') Owner: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') Reader: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') - 'Role Based Access Control Administrator (Preview)': subscriptionResourceId( + 'Role Based Access Control Administrator': subscriptionResourceId( 'Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' ) @@ -403,7 +403,7 @@ resource cognitiveService_diagnosticSettings 'Microsoft.Insights/diagnosticSetti } ] -module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.6.1' = [ +module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.8.0' = [ for (privateEndpoint, index) in (privateEndpoints ?? []): { name: '${uniqueString(deployment().name, location)}-cognitiveService-PrivateEndpoint-${index}' scope: resourceGroup(privateEndpoint.?resourceGroupName ?? '') @@ -444,8 +444,7 @@ module cognitiveService_privateEndpoints 'br/public:avm/res/network/private-endp 'Full' ).location lock: privateEndpoint.?lock ?? lock - privateDnsZoneGroupName: privateEndpoint.?privateDnsZoneGroupName - privateDnsZoneResourceIds: privateEndpoint.?privateDnsZoneResourceIds + privateDnsZoneGroup: privateEndpoint.?privateDnsZoneGroup roleAssignments: privateEndpoint.?roleAssignments tags: privateEndpoint.?tags ?? tags customDnsConfigs: privateEndpoint.?customDnsConfigs @@ -528,6 +527,17 @@ output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) : {} +@description('The private endpoints of the congitive services account.') +output privateEndpoints array = [ + for (pe, i) in (!empty(privateEndpoints) ? array(privateEndpoints) : []): { + name: cognitiveService_privateEndpoints[i].outputs.name + resourceId: cognitiveService_privateEndpoints[i].outputs.resourceId + groupId: cognitiveService_privateEndpoints[i].outputs.groupId + customDnsConfig: cognitiveService_privateEndpoints[i].outputs.customDnsConfig + networkInterfaceIds: cognitiveService_privateEndpoints[i].outputs.networkInterfaceIds + } +] + // ================ // // Definitions // // ================ // @@ -618,11 +628,20 @@ type privateEndpointType = { @description('Required. Resource ID of the subnet where the endpoint needs to be created.') subnetResourceId: string - @description('Optional. The name of the private DNS zone group to create if `privateDnsZoneResourceIds` were provided.') - privateDnsZoneGroupName: string? + @description('Optional. The private DNS zone group to configure for the private endpoint.') + privateDnsZoneGroup: { + @description('Optional. The name of the Private DNS Zone Group.') + name: string? - @description('Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones.') - privateDnsZoneResourceIds: string[]? + @description('Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones.') + privateDnsZoneGroupConfigs: { + @description('Optional. The name of the private DNS zone group config.') + name: string? + + @description('Required. The resource id of the private DNS zone.') + privateDnsZoneResourceId: string + }[] + }? @description('Optional. If Manual Private Link Connection is required.') isManualConnection: bool? diff --git a/avm/res/cognitive-services/account/main.json b/avm/res/cognitive-services/account/main.json index b1c8468f51..c2ce82cbd8 100644 --- a/avm/res/cognitive-services/account/main.json +++ b/avm/res/cognitive-services/account/main.json @@ -6,7 +6,7 @@ "_generator": { "name": "bicep", "version": "0.30.23.60470", - "templateHash": "4946778004284930976" + "templateHash": "11788701359615687264" }, "name": "Cognitive Services", "description": "This module deploys a Cognitive Service.", @@ -245,21 +245,44 @@ "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" + "privateDnsZoneGroup": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + } + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } }, "nullable": true, "metadata": { - "description": "Optional. The private DNS zone groups to associate the private endpoint with. A DNS zone group can support up to 5 DNS zones." + "description": "Optional. The private DNS zone group to configure for the private endpoint." } }, "isManualConnection": { @@ -887,7 +910,7 @@ "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" } }, @@ -1100,11 +1123,8 @@ "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')]" + "privateDnsZoneGroup": { + "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'privateDnsZoneGroup')]" }, "roleAssignments": { "value": "[tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'roleAssignments')]" @@ -1133,13 +1153,34 @@ "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "13720311665093076615" + "templateHash": "10193943972635711937" }, "name": "Private Endpoints", "description": "This module deploys a Private Endpoint.", "owner": "Azure/module-maintainers" }, "definitions": { + "privateDnsZoneGroupType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the Private DNS Zone Group." + } + }, + "privateDnsZoneGroupConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, + "metadata": { + "description": "Required. The private DNS zone groups to associate the private endpoint. A DNS zone group can support up to 5 DNS zones." + } + } + } + }, "roleAssignmentType": { "type": "array", "items": { @@ -1391,6 +1432,29 @@ } }, "nullable": true + }, + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "private-dns-zone-group/main.bicep" + } + } } }, "parameters": { @@ -1426,18 +1490,11 @@ "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", + "privateDnsZoneGroup": { + "$ref": "#/definitions/privateDnsZoneGroupType", "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." + "description": "Optional. The private DNS zone group to configure for the private endpoint." } }, "location": { @@ -1510,7 +1567,7 @@ "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", "Private DNS Zone Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b12aa53e-6015-4669-85d0-8515ebb3ae7f')]", "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", - "Role Based Access Control Administrator (Preview)": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]" } }, "resources": { @@ -1518,7 +1575,7 @@ "condition": "[parameters('enableTelemetry')]", "type": "Microsoft.Resources/deployments", "apiVersion": "2024-03-01", - "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.6.1', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", + "name": "[format('46d3xbcp.res.network-privateendpoint.{0}.{1}', replace('0.8.0', '.', '-'), substring(uniqueString(deployment().name, parameters('location')), 0, 4))]", "properties": { "mode": "Incremental", "template": { @@ -1597,7 +1654,7 @@ ] }, "privateEndpoint_privateDnsZoneGroup": { - "condition": "[not(empty(parameters('privateDnsZoneResourceIds')))]", + "condition": "[not(empty(parameters('privateDnsZoneGroup')))]", "type": "Microsoft.Resources/deployments", "apiVersion": "2022-09-01", "name": "[format('{0}-PrivateEndpoint-PrivateDnsZoneGroup', uniqueString(deployment().name))]", @@ -1608,28 +1665,52 @@ "mode": "Incremental", "parameters": { "name": { - "value": "[coalesce(parameters('privateDnsZoneGroupName'), 'default')]" - }, - "privateDNSResourceIds": { - "value": "[coalesce(parameters('privateDnsZoneResourceIds'), createArray())]" + "value": "[tryGet(parameters('privateDnsZoneGroup'), 'name')]" }, "privateEndpointName": { "value": "[parameters('name')]" + }, + "privateDnsZoneConfigs": { + "value": "[parameters('privateDnsZoneGroup').privateDnsZoneGroupConfigs]" } }, "template": { "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", "contentVersion": "1.0.0.0", "metadata": { "_generator": { "name": "bicep", "version": "0.29.47.4906", - "templateHash": "15263454436186512874" + "templateHash": "5805178546717255803" }, "name": "Private Endpoint Private DNS Zone Groups", "description": "This module deploys a Private Endpoint Private DNS Zone Group.", "owner": "Azure/module-maintainers" }, + "definitions": { + "privateDnsZoneGroupConfigType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of the private DNS zone group config." + } + }, + "privateDnsZoneResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource id of the private DNS zone." + } + } + }, + "metadata": { + "__bicep_export!": true + } + } + }, "parameters": { "privateEndpointName": { "type": "string", @@ -1637,12 +1718,15 @@ "description": "Conditional. The name of the parent private endpoint. Required if the template is used in a standalone deployment." } }, - "privateDNSResourceIds": { + "privateDnsZoneConfigs": { "type": "array", + "items": { + "$ref": "#/definitions/privateDnsZoneGroupConfigType" + }, "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." + "description": "Required. Array of private DNS zone configurations of the private DNS zone group. A DNS zone group can support up to 5 DNS zones." } }, "name": { @@ -1656,27 +1740,36 @@ "variables": { "copy": [ { - "name": "privateDnsZoneConfigs", - "count": "[length(parameters('privateDNSResourceIds'))]", + "name": "privateDnsZoneConfigsVar", + "count": "[length(parameters('privateDnsZoneConfigs'))]", "input": { - "name": "[last(split(parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')], '/'))]", + "name": "[coalesce(tryGet(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')], 'name'), last(split(parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId, '/')))]", "properties": { - "privateDnsZoneId": "[parameters('privateDNSResourceIds')[copyIndex('privateDnsZoneConfigs')]]" + "privateDnsZoneId": "[parameters('privateDnsZoneConfigs')[copyIndex('privateDnsZoneConfigsVar')].privateDnsZoneResourceId]" } } } ] }, - "resources": [ - { + "resources": { + "privateEndpoint": { + "existing": true, + "type": "Microsoft.Network/privateEndpoints", + "apiVersion": "2023-11-01", + "name": "[parameters('privateEndpointName')]" + }, + "privateDnsZoneGroup": { "type": "Microsoft.Network/privateEndpoints/privateDnsZoneGroups", "apiVersion": "2023-11-01", "name": "[format('{0}/{1}', parameters('privateEndpointName'), parameters('name'))]", "properties": { - "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigs')]" - } + "privateDnsZoneConfigs": "[variables('privateDnsZoneConfigsVar')]" + }, + "dependsOn": [ + "privateEndpoint" + ] } - ], + }, "outputs": { "name": { "type": "string", @@ -1743,6 +1836,13 @@ }, "value": "[reference('privateEndpoint').customDnsConfigs]" }, + "networkInterfaceIds": { + "type": "array", + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + }, + "value": "[reference('privateEndpoint').networkInterfaces]" + }, "groupId": { "type": "string", "metadata": { @@ -1948,6 +2048,22 @@ "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." }, "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + }, + "privateEndpoints": { + "type": "array", + "metadata": { + "description": "The private endpoints of the congitive services account." + }, + "copy": { + "count": "[length(if(not(empty(parameters('privateEndpoints'))), array(parameters('privateEndpoints')), createArray()))]", + "input": { + "name": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.groupId.value]", + "customDnsConfig": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfig.value]", + "networkInterfaceIds": "[reference(format('cognitiveService_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceIds.value]" + } + } } } } \ No newline at end of file diff --git a/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment-private/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment-private/main.test.bicep index fda05f65f1..2c500d20a3 100644 --- a/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment-private/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/ai-model-deployment-private/main.test.bicep @@ -41,7 +41,6 @@ module nestedDependencies 'dependencies.bicep' = { } } - // ============== // // Test Execution // // ============== // @@ -72,10 +71,16 @@ module testDeployment '../../../main.bicep' = [ publicNetworkAccess: 'Disabled' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - nestedDependencies.outputs.privateDNSZoneOpenAIResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneOpenAIResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId } ] diff --git a/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep index 86f9529a0f..80c3f084d2 100644 --- a/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/max/main.test.bicep @@ -140,9 +140,13 @@ module testDeployment '../../../main.bicep' = [ } privateEndpoints: [ { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId tags: { 'hidden-title': 'This is visible in the resource name' @@ -169,9 +173,13 @@ module testDeployment '../../../main.bicep' = [ ] } { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId } ] diff --git a/avm/res/cognitive-services/account/tests/e2e/openai-private/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/openai-private/main.test.bicep index 046f81ead1..ef683ee0aa 100644 --- a/avm/res/cognitive-services/account/tests/e2e/openai-private/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/openai-private/main.test.bicep @@ -41,7 +41,6 @@ module nestedDependencies 'dependencies.bicep' = { } } - // ============== // // Test Execution // // ============== // @@ -72,9 +71,13 @@ module testDeployment '../../../main.bicep' = [ publicNetworkAccess: 'Disabled' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId } ] diff --git a/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep index a4c8eb799b..776dfdad0e 100644 --- a/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/speech/main.test.bicep @@ -56,9 +56,13 @@ module testDeployment '../../../main.bicep' = [ customSubDomainName: '${namePrefix}speechdomain' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep b/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep index 53649ec3f4..70f18da307 100644 --- a/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep +++ b/avm/res/cognitive-services/account/tests/e2e/waf-aligned/main.test.bicep @@ -83,9 +83,13 @@ module testDeployment '../../../main.bicep' = [ sku: 'S0' privateEndpoints: [ { - privateDnsZoneResourceIds: [ - nestedDependencies.outputs.privateDNSZoneResourceId - ] + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } subnetResourceId: nestedDependencies.outputs.subnetResourceId tags: { 'hidden-title': 'This is visible in the resource name' diff --git a/avm/res/cognitive-services/account/version.json b/avm/res/cognitive-services/account/version.json index 7e1d3f4157..0f81d22abc 100644 --- a/avm/res/cognitive-services/account/version.json +++ b/avm/res/cognitive-services/account/version.json @@ -1,6 +1,6 @@ { "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", - "version": "0.7", + "version": "0.8", "pathFilters": [ "./main.json" ]