diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fff88d76bc..2e2123c29c 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -66,6 +66,7 @@ /avm/res/dev-test-lab/lab/ @Azure/avm-res-devtestlab-lab-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/digital-twins/digital-twins-instance/ @Azure/avm-res-digitaltwins-digitaltwinsinstance-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/document-db/database-account/ @Azure/avm-res-documentdb-databaseaccount-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/res/document-db/mongo-cluster/ @Azure/avm-res-documentdb-mongocluster-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-grid/domain/ @Azure/avm-res-eventgrid-domain-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-grid/namespace/ @Azure/avm-res-eventgrid-namespace-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/event-grid/system-topic/ @Azure/avm-res-eventgrid-systemtopic-module-owners-bicep @Azure/avm-module-reviewers-bicep diff --git a/.github/ISSUE_TEMPLATE/avm_module_issue.yml b/.github/ISSUE_TEMPLATE/avm_module_issue.yml index feded8d600..d9e7855858 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -101,6 +101,7 @@ body: - "avm/res/dev-test-lab/lab" - "avm/res/digital-twins/digital-twins-instance" - "avm/res/document-db/database-account" + - "avm/res/document-db/mongo-cluster" - "avm/res/event-grid/domain" - "avm/res/event-grid/namespace" - "avm/res/event-grid/system-topic" diff --git a/.github/workflows/avm.res.document-db.mongo-cluster.yml b/.github/workflows/avm.res.document-db.mongo-cluster.yml new file mode 100644 index 0000000000..f7b513ae03 --- /dev/null +++ b/.github/workflows/avm.res.document-db.mongo-cluster.yml @@ -0,0 +1,88 @@ +name: "avm.res.document-db.mongo-cluster" + +on: + workflow_dispatch: + inputs: + staticValidation: + type: boolean + description: "Execute static validation" + required: false + default: true + deploymentValidation: + type: boolean + description: "Execute deployment validation" + required: false + default: true + removeDeployment: + type: boolean + description: "Remove deployed module" + required: false + default: true + customLocation: + type: string + description: "Default location overwrite (e.g., eastus)" + required: false + push: + branches: + - main + paths: + - ".github/actions/templates/avm-**" + - ".github/workflows/avm.template.module.yml" + - ".github/workflows/avm.res.document-db.mongo-cluster.yml" + - "avm/res/document-db/mongo-cluster/**" + - "avm/utilities/pipelines/**" + - "!avm/utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/document-db/mongo-cluster" + workflowPath: ".github/workflows/avm.res.document-db.mongo-cluster.yml" + +concurrency: + group: ${{ github.workflow }} + +jobs: + ########################### + # Initialize pipeline # + ########################### + job_initialize_pipeline: + runs-on: ubuntu-latest + name: "Initialize pipeline" + steps: + - name: "Checkout" + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: "Set input parameters to output variables" + id: get-workflow-param + uses: ./.github/actions/templates/avm-getWorkflowInput + with: + workflowPath: "${{ env.workflowPath}}" + - name: "Get module test file paths" + id: get-module-test-file-paths + uses: ./.github/actions/templates/avm-getModuleTestFiles + with: + modulePath: "${{ env.modulePath }}" + outputs: + workflowInput: ${{ steps.get-workflow-param.outputs.workflowInput }} + moduleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.moduleTestFilePaths }} + psRuleModuleTestFilePaths: ${{ steps.get-module-test-file-paths.outputs.psRuleModuleTestFilePaths }} + modulePath: "${{ env.modulePath }}" + + ############################## + # Call reusable workflow # + ############################## + call-workflow-passing-data: + name: "Run" + permissions: + id-token: write # For OIDC + contents: write # For release tags + needs: + - job_initialize_pipeline + uses: ./.github/workflows/avm.template.module.yml + with: + workflowInput: "${{ needs.job_initialize_pipeline.outputs.workflowInput }}" + moduleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.moduleTestFilePaths }}" + psRuleModuleTestFilePaths: "${{ needs.job_initialize_pipeline.outputs.psRuleModuleTestFilePaths }}" + modulePath: "${{ needs.job_initialize_pipeline.outputs.modulePath}}" + secrets: inherit diff --git a/avm/res/document-db/mongo-cluster/README.md b/avm/res/document-db/mongo-cluster/README.md new file mode 100644 index 0000000000..c4af03e2b4 --- /dev/null +++ b/avm/res/document-db/mongo-cluster/README.md @@ -0,0 +1,1393 @@ +# Azure Cosmos DB MongoDB vCore cluster `[Microsoft.DocumentDB/mongoClusters]` + +This module deploys a Azure Cosmos DB MongoDB vCore cluster. + +**Note:** This module is not intended for broad, generic use, as it was designed to cater for the requirements of the AZD CLI product. Feature requests and bug fix requests are welcome if they support the development of the AZD CLI but may not be incorporated if they aim to make this module more generic than what it needs to be for its primary use case. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Usage examples](#Usage-examples) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) +- [Data Collection](#Data-Collection) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | [2020-05-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-05-01/locks) | +| `Microsoft.Authorization/roleAssignments` | [2022-04-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2022-04-01/roleAssignments) | +| `Microsoft.DocumentDB/mongoClusters` | [2024-02-15-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DocumentDB/2024-02-15-preview/mongoClusters) | +| `Microsoft.DocumentDB/mongoClusters/firewallRules` | [2024-02-15-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.DocumentDB/2024-02-15-preview/mongoClusters/firewallRules) | +| `Microsoft.Insights/diagnosticSettings` | [2021-05-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Insights/2021-05-01-preview/diagnosticSettings) | +| `Microsoft.KeyVault/vaults/secrets` | [2023-07-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.KeyVault/2023-07-01/vaults/secrets) | +| `Microsoft.Network/privateEndpoints` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints) | +| `Microsoft.Network/privateEndpoints/privateDnsZoneGroups` | [2023-11-01](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Network/2023-11-01/privateEndpoints/privateDnsZoneGroups) | + +## Usage examples + +The following section provides usage examples for the module, which were used to validate and deploy the module successfully. For a full reference, please review the module's test folder in its repository. + +>**Note**: Each example lists all the required parameters first, followed by the rest - each in alphabetical order. + +>**Note**: To reference the module, please use the following syntax `br/public:avm/res/document-db/mongo-cluster:`. + +- [Using only defaults](#example-1-using-only-defaults) +- [Deploying with a key vault reference to save secrets](#example-2-deploying-with-a-key-vault-reference-to-save-secrets) +- [Using large parameter set](#example-3-using-large-parameter-set) +- [WAF-aligned](#example-4-waf-aligned) + +### Example 1: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +
+ +via Bicep module + +```bicep +module mongoCluster 'br/public:avm/res/document-db/mongo-cluster:' = { + name: 'mongoClusterDeployment' + params: { + // Required parameters + administratorLogin: 'Admin001' + administratorLoginPassword: '' + name: 'ddmcdefmin001' + nodeCount: 2 + sku: 'M30' + storage: 256 + // Non-required parameters + location: '' + } +} +``` + +
+

+ +

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

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

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

+ +

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

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

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

+ +

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

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

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

+ +

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

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