From d91e5e5208a8d2be74dea1990f9f9af3b69897f0 Mon Sep 17 00:00:00 2001 From: JeffreyCA Date: Wed, 19 Feb 2025 09:50:51 -0800 Subject: [PATCH] feat: New module `avm/res/cache/redis-enterprise` - Redis Enterprise and Azure Managed Redis (Preview) (#4114) ## Description Initial implementation of Bicep AVM for Redis Enterprise and Azure Managed Redis (Preview) caches (`Microsoft.Cache/redisEnterprise`). There is a related module, [`avm/res/cache/redis`](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res/cache/redis), that covers `Microsoft.Cache/redis`: | Module Name | Resource Type | SKUs | |----------------------------|--------------------------------|--------------------------------------------------------------------------------------------| | [`avm/res/cache/redis`](https://github.com/Azure/bicep-registry-modules/tree/main/avm/res/cache/redis) | Microsoft.Cache/redis | **OSS Redis:** Basic, Standard, Premium | | `avm/res/cache/redis-enterprise` (this PR) | Microsoft.Cache/redisEnterprise | **Redis Enterprise:** Enterprise, Enterprise Flash
**Azure Managed Redis (Preview):** Balanced, Compute Optimized, Flash Optimized, Memory Optimized | ![image](https://github.com/user-attachments/assets/7128fcea-0708-4ae5-b2ed-8e1e1b9dd6ff) Closes https://github.com/Azure/Azure-Verified-Modules/issues/1731. ## Pipeline Reference I'm facing issues setting up CI on my fork using my Azure subscription and Service Principal in the Microsoft tenant, but was able to validate all the E2E tests passed using [`Test-ModuleLocally.ps1`](https://github.com/Azure/bicep-registry-modules/blob/main/utilities/tools/Test-ModuleLocally.ps1). ![image](https://github.com/user-attachments/assets/9a8de7d8-598e-41b0-8ebc-3ae68ceb697b) | Pipeline | | -------- | | | ## Type of Change - [ ] Update to CI Environment or utilities (Non-module affecting changes) - [x] Azure Verified Module updates: - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`: - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description. - [ ] The bug was found by the module author, and no one has opened an issue to report it yet. - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`. - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`. - [x] Update to documentation ## Checklist - [x] I'm sure there are no other open Pull Requests for the same update/change - [x] I have run `Set-AVMModule` locally to generate the supporting module files. - [ ] My corresponding pipelines / checks run clean and green without any errors or warnings --- .github/CODEOWNERS | 1 + .github/ISSUE_TEMPLATE/avm_module_issue.yml | 1 + .../avm.res.cache.redis-enterprise.yml | 88 + avm/res/cache/redis-enterprise/README.md | 2659 +++++++++++++ .../cache/redis-enterprise/database/README.md | 521 +++ .../access-policy-assignment/README.md | 88 + .../access-policy-assignment/main.bicep | 51 + .../access-policy-assignment/main.json | 106 + .../redis-enterprise/database/main.bicep | 329 ++ .../cache/redis-enterprise/database/main.json | 933 +++++ .../database/modules/keyVaultExport.bicep | 43 + avm/res/cache/redis-enterprise/main.bicep | 517 +++ avm/res/cache/redis-enterprise/main.json | 3312 +++++++++++++++++ .../active-geo-replication/dependencies.bicep | 42 + .../active-geo-replication/main.test.bicep | 74 + .../tests/e2e/amr-entra-id/dependencies.bicep | 13 + .../tests/e2e/amr-entra-id/main.test.bicep | 68 + .../tests/e2e/amr/main.test.bicep | 49 + .../tests/e2e/defaults/main.test.bicep | 48 + .../tests/e2e/kv-secrets/dependencies.bicep | 21 + .../tests/e2e/kv-secrets/main.test.bicep | 62 + .../tests/e2e/max/dependencies.bicep | 63 + .../tests/e2e/max/main.test.bicep | 175 + .../dependencies.bicep | 63 + .../main.test.bicep | 75 + .../tests/e2e/waf-aligned/dependencies.bicep | 49 + .../tests/e2e/waf-aligned/main.test.bicep | 132 + avm/res/cache/redis-enterprise/version.json | 7 + 28 files changed, 9590 insertions(+) create mode 100644 .github/workflows/avm.res.cache.redis-enterprise.yml create mode 100644 avm/res/cache/redis-enterprise/README.md create mode 100644 avm/res/cache/redis-enterprise/database/README.md create mode 100644 avm/res/cache/redis-enterprise/database/access-policy-assignment/README.md create mode 100644 avm/res/cache/redis-enterprise/database/access-policy-assignment/main.bicep create mode 100644 avm/res/cache/redis-enterprise/database/access-policy-assignment/main.json create mode 100644 avm/res/cache/redis-enterprise/database/main.bicep create mode 100644 avm/res/cache/redis-enterprise/database/main.json create mode 100644 avm/res/cache/redis-enterprise/database/modules/keyVaultExport.bicep create mode 100644 avm/res/cache/redis-enterprise/main.bicep create mode 100644 avm/res/cache/redis-enterprise/main.json create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/active-geo-replication/dependencies.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/active-geo-replication/main.test.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/amr-entra-id/dependencies.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/amr-entra-id/main.test.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/amr/main.test.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/defaults/main.test.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/kv-secrets/dependencies.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/kv-secrets/main.test.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/max/dependencies.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/max/main.test.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/user-assigned-cmk-encryption/main.test.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/waf-aligned/dependencies.bicep create mode 100644 avm/res/cache/redis-enterprise/tests/e2e/waf-aligned/main.test.bicep create mode 100644 avm/res/cache/redis-enterprise/version.json diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index e2ab1172d0..a707f92544 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -50,6 +50,7 @@ /avm/res/azure-stack-hci/cluster/ @Azure/avm-res-azurestackhci-cluster-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/batch/batch-account/ @Azure/avm-res-batch-batchaccount-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/cache/redis/ @Azure/avm-res-cache-redis-module-owners-bicep @Azure/avm-module-reviewers-bicep +/avm/res/cache/redis-enterprise/ @Azure/avm-res-cache-redisenterprise-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/cdn/profile/ @Azure/avm-res-cdn-profile-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/cognitive-services/account/ @Azure/avm-res-cognitiveservices-account-module-owners-bicep @Azure/avm-module-reviewers-bicep /avm/res/communication/communication-service/ @Azure/avm-res-communication-communicationservice-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 871a9782a5..dd19aa2898 100644 --- a/.github/ISSUE_TEMPLATE/avm_module_issue.yml +++ b/.github/ISSUE_TEMPLATE/avm_module_issue.yml @@ -85,6 +85,7 @@ body: - "avm/res/azure-stack-hci/cluster" - "avm/res/batch/batch-account" - "avm/res/cache/redis" + - "avm/res/cache/redis-enterprise" - "avm/res/cdn/profile" - "avm/res/cognitive-services/account" - "avm/res/communication/communication-service" diff --git a/.github/workflows/avm.res.cache.redis-enterprise.yml b/.github/workflows/avm.res.cache.redis-enterprise.yml new file mode 100644 index 0000000000..7cdf12fdd4 --- /dev/null +++ b/.github/workflows/avm.res.cache.redis-enterprise.yml @@ -0,0 +1,88 @@ +name: "avm.res.cache.redis-enterprise" + +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.cache.redis-enterprise.yml" + - "avm/res/cache/redis-enterprise/**" + - "utilities/pipelines/**" + - "!utilities/pipelines/platform/**" + - "!*/**/README.md" + +env: + modulePath: "avm/res/cache/redis-enterprise" + workflowPath: ".github/workflows/avm.res.cache.redis-enterprise.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/cache/redis-enterprise/README.md b/avm/res/cache/redis-enterprise/README.md new file mode 100644 index 0000000000..5dc42f9da4 --- /dev/null +++ b/avm/res/cache/redis-enterprise/README.md @@ -0,0 +1,2659 @@ +# Redis Enterprise and Azure Managed Redis (Preview) `[Microsoft.Cache/redisEnterprise]` + +This module deploys a Redis Enterprise or Azure Managed Redis (Preview) cache. + +## 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.Cache/redisEnterprise` | [2024-09-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cache/2024-09-01-preview/redisEnterprise) | +| `Microsoft.Cache/redisEnterprise/databases` | [2024-09-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cache/2024-09-01-preview/redisEnterprise/databases) | +| `Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments` | [2024-09-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cache/2024-09-01-preview/redisEnterprise/databases/accessPolicyAssignments) | +| `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/cache/redis-enterprise:`. + +- [Active geo-replication](#example-1-active-geo-replication) +- [Azure Managed Redis (Preview) with Entra ID authentication](#example-2-azure-managed-redis-preview-with-entra-id-authentication) +- [Azure Managed Redis (Preview)](#example-3-azure-managed-redis-preview) +- [Using only defaults](#example-4-using-only-defaults) +- [Deploying with a key vault reference to save secrets](#example-5-deploying-with-a-key-vault-reference-to-save-secrets) +- [Using large parameter set](#example-6-using-large-parameter-set) +- [Using Customer-Managed-Keys with User-Assigned identity](#example-7-using-customer-managed-keys-with-user-assigned-identity) +- [WAF-aligned](#example-8-waf-aligned) + +### Example 1: _Active geo-replication_ + +This instance deploys the module with active geo-replication enabled. + + +
+ +via Bicep module + +```bicep +module redisEnterprise 'br/public:avm/res/cache/redis-enterprise:' = { + name: 'redisEnterpriseDeployment' + params: { + // Required parameters + name: 'creagr002' + // Non-required parameters + database: { + geoReplication: { + groupNickname: '' + linkedDatabases: [ + { + id: '' + } + { + id: '' + } + ] + } + } + location: '' + skuName: 'Balanced_B10' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "creagr002" + }, + // Non-required parameters + "database": { + "value": { + "geoReplication": { + "groupNickname": "", + "linkedDatabases": [ + { + "id": "" + }, + { + "id": "" + } + ] + } + } + }, + "location": { + "value": "" + }, + "skuName": { + "value": "Balanced_B10" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis-enterprise:' + +// Required parameters +param name = 'creagr002' +// Non-required parameters +param database = { + geoReplication: { + groupNickname: '' + linkedDatabases: [ + { + id: '' + } + { + id: '' + } + ] + } +} +param location = '' +param skuName = 'Balanced_B10' +``` + +
+

+ +### Example 2: _Azure Managed Redis (Preview) with Entra ID authentication_ + +This instance deploys an Azure Managed Redis (Preview) cache with Entra ID authentication. + + +

+ +via Bicep module + +```bicep +module redisEnterprise 'br/public:avm/res/cache/redis-enterprise:' = { + name: 'redisEnterpriseDeployment' + params: { + // Required parameters + name: 'creaei001' + // Non-required parameters + database: { + accessKeysAuthentication: 'Disabled' + accessPolicyAssignments: [ + { + name: 'assign1' + userObjectId: '' + } + ] + } + location: '' + skuName: 'Balanced_B10' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "creaei001" + }, + // Non-required parameters + "database": { + "value": { + "accessKeysAuthentication": "Disabled", + "accessPolicyAssignments": [ + { + "name": "assign1", + "userObjectId": "" + } + ] + } + }, + "location": { + "value": "" + }, + "skuName": { + "value": "Balanced_B10" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis-enterprise:' + +// Required parameters +param name = 'creaei001' +// Non-required parameters +param database = { + accessKeysAuthentication: 'Disabled' + accessPolicyAssignments: [ + { + name: 'assign1' + userObjectId: '' + } + ] +} +param location = '' +param skuName = 'Balanced_B10' +``` + +
+

+ +### Example 3: _Azure Managed Redis (Preview)_ + +This instance deploys an Azure Managed Redis (Preview) cache with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module redisEnterprise 'br/public:avm/res/cache/redis-enterprise:' = { + name: 'redisEnterpriseDeployment' + params: { + // Required parameters + name: 'creamr001' + // Non-required parameters + skuName: 'Balanced_B10' + } +} +``` + +
+

+ +

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

+ +

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

+ +### Example 4: _Using only defaults_ + +This instance deploys the module with the minimum set of required parameters. + + +

+ +via Bicep module + +```bicep +module redisEnterprise 'br/public:avm/res/cache/redis-enterprise:' = { + name: 'redisEnterpriseDeployment' + params: { + // Required parameters + name: 'cremin001' + // Non-required parameters + skuName: 'Balanced_B10' + } +} +``` + +
+

+ +

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

+ +

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

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

+ +via Bicep module + +```bicep +module redisEnterprise 'br/public:avm/res/cache/redis-enterprise:' = { + name: 'redisEnterpriseDeployment' + params: { + // Required parameters + name: 'kvref' + // Non-required parameters + database: { + secretsExportConfiguration: { + keyVaultResourceId: '' + primaryAccessKeyName: 'custom-primaryAccessKey-name' + primaryConnectionStringName: 'custom-primaryConnectionString-name' + primaryStackExchangeRedisConnectionStringName: 'custom-primaryStackExchangeRedisConnectionString-name' + secondaryAccessKeyName: 'custom-secondaryAccessKey-name' + secondaryConnectionStringName: 'custom-secondaryConnectionString-name' + secondaryStackExchangeRedisConnectionStringName: 'custom-secondaryStackExchangeRedisConnectionString-name' + } + } + skuName: 'Balanced_B10' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "kvref" + }, + // Non-required parameters + "database": { + "value": { + "secretsExportConfiguration": { + "keyVaultResourceId": "", + "primaryAccessKeyName": "custom-primaryAccessKey-name", + "primaryConnectionStringName": "custom-primaryConnectionString-name", + "primaryStackExchangeRedisConnectionStringName": "custom-primaryStackExchangeRedisConnectionString-name", + "secondaryAccessKeyName": "custom-secondaryAccessKey-name", + "secondaryConnectionStringName": "custom-secondaryConnectionString-name", + "secondaryStackExchangeRedisConnectionStringName": "custom-secondaryStackExchangeRedisConnectionString-name" + } + } + }, + "skuName": { + "value": "Balanced_B10" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis-enterprise:' + +// Required parameters +param name = 'kvref' +// Non-required parameters +param database = { + secretsExportConfiguration: { + keyVaultResourceId: '' + primaryAccessKeyName: 'custom-primaryAccessKey-name' + primaryConnectionStringName: 'custom-primaryConnectionString-name' + primaryStackExchangeRedisConnectionStringName: 'custom-primaryStackExchangeRedisConnectionString-name' + secondaryAccessKeyName: 'custom-secondaryAccessKey-name' + secondaryConnectionStringName: 'custom-secondaryConnectionString-name' + secondaryStackExchangeRedisConnectionStringName: 'custom-secondaryStackExchangeRedisConnectionString-name' + } +} +param skuName = 'Balanced_B10' +``` + +
+

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

+ +via Bicep module + +```bicep +module redisEnterprise 'br/public:avm/res/cache/redis-enterprise:' = { + name: 'redisEnterpriseDeployment' + params: { + // Required parameters + name: 'cremax001' + // Non-required parameters + database: { + clientProtocol: 'Plaintext' + clusteringPolicy: 'EnterpriseCluster' + deferUpgrade: 'Deferred' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSettingDatabase' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + evictionPolicy: 'NoEviction' + modules: [ + { + name: 'RedisBloom' + } + { + name: 'RediSearch' + } + ] + persistence: { + frequency: '1s' + type: 'aof' + } + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSettingCluster' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + enableTelemetry: true + highAvailability: 'Disabled' + location: '' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + minimumTlsVersion: '1.2' + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + roleAssignments: [ + { + name: '759769d2-fc52-4a92-a943-724e48927e0b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } + ] + skuName: 'Balanced_B10' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + 3 + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "cremax001" + }, + // Non-required parameters + "database": { + "value": { + "clientProtocol": "Plaintext", + "clusteringPolicy": "EnterpriseCluster", + "deferUpgrade": "Deferred", + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs" + } + ], + "name": "customSettingDatabase", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "evictionPolicy": "NoEviction", + "modules": [ + { + "name": "RedisBloom" + }, + { + "name": "RediSearch" + } + ], + "persistence": { + "frequency": "1s", + "type": "aof" + } + } + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSettingCluster", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "enableTelemetry": { + "value": true + }, + "highAvailability": { + "value": "Disabled" + }, + "location": { + "value": "" + }, + "lock": { + "value": { + "kind": "CanNotDelete", + "name": "myCustomLockName" + } + }, + "minimumTlsVersion": { + "value": "1.2" + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, + "roleAssignments": { + "value": [ + { + "name": "759769d2-fc52-4a92-a943-724e48927e0b", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "Owner" + }, + { + "name": "", + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "b24988ac-6180-42a0-ab88-20f7382dd24c" + }, + { + "principalId": "", + "principalType": "ServicePrincipal", + "roleDefinitionIdOrName": "" + } + ] + }, + "skuName": { + "value": "Balanced_B10" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "zones": { + "value": [ + 1, + 2, + 3 + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis-enterprise:' + +// Required parameters +param name = 'cremax001' +// Non-required parameters +param database = { + clientProtocol: 'Plaintext' + clusteringPolicy: 'EnterpriseCluster' + deferUpgrade: 'Deferred' + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSettingDatabase' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + evictionPolicy: 'NoEviction' + modules: [ + { + name: 'RedisBloom' + } + { + name: 'RediSearch' + } + ] + persistence: { + frequency: '1s' + type: 'aof' + } +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSettingCluster' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param enableTelemetry = true +param highAvailability = 'Disabled' +param location = '' +param lock = { + kind: 'CanNotDelete' + name: 'myCustomLockName' +} +param minimumTlsVersion = '1.2' +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param roleAssignments = [ + { + name: '759769d2-fc52-4a92-a943-724e48927e0b' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'Owner' + } + { + name: '' + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + } + { + principalId: '' + principalType: 'ServicePrincipal' + roleDefinitionIdOrName: '' + } +] +param skuName = 'Balanced_B10' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zones = [ + 1 + 2 + 3 +] +``` + +
+

+ +### Example 7: _Using Customer-Managed-Keys with User-Assigned identity_ + +This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret. + + +

+ +via Bicep module + +```bicep +module redisEnterprise 'br/public:avm/res/cache/redis-enterprise:' = { + name: 'redisEnterpriseDeployment' + params: { + // Required parameters + name: 'creuace001' + // Non-required parameters + customerManagedKey: { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' + } + database: { + persistence: { + frequency: '6h' + type: 'rdb' + } + } + managedIdentities: { + userAssignedResourceIds: [ + '' + ] + } + skuName: 'Balanced_B10' + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "creuace001" + }, + // Non-required parameters + "customerManagedKey": { + "value": { + "keyName": "", + "keyVaultResourceId": "", + "userAssignedIdentityResourceId": "" + } + }, + "database": { + "value": { + "persistence": { + "frequency": "6h", + "type": "rdb" + } + } + }, + "managedIdentities": { + "value": { + "userAssignedResourceIds": [ + "" + ] + } + }, + "skuName": { + "value": "Balanced_B10" + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis-enterprise:' + +// Required parameters +param name = 'creuace001' +// Non-required parameters +param customerManagedKey = { + keyName: '' + keyVaultResourceId: '' + userAssignedIdentityResourceId: '' +} +param database = { + persistence: { + frequency: '6h' + type: 'rdb' + } +} +param managedIdentities = { + userAssignedResourceIds: [ + '' + ] +} +param skuName = 'Balanced_B10' +``` + +
+

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

+ +via Bicep module + +```bicep +module redisEnterprise 'br/public:avm/res/cache/redis-enterprise:' = { + name: 'redisEnterpriseDeployment' + params: { + // Required parameters + name: 'crewaf001' + // Non-required parameters + database: { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSettingDatabase' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + persistence: { + frequency: '1h' + type: 'rdb' + } + } + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSettingCluster' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } + ] + skuName: 'Balanced_B10' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + 3 + ] + } +} +``` + +
+

+ +

+ +via JSON parameters file + +```json +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + // Required parameters + "name": { + "value": "crewaf001" + }, + // Non-required parameters + "database": { + "value": { + "diagnosticSettings": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "logCategoriesAndGroups": [ + { + "categoryGroup": "allLogs" + } + ], + "name": "customSettingDatabase", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ], + "persistence": { + "frequency": "1h", + "type": "rdb" + } + } + }, + "diagnosticSettings": { + "value": [ + { + "eventHubAuthorizationRuleResourceId": "", + "eventHubName": "", + "metricCategories": [ + { + "category": "AllMetrics" + } + ], + "name": "customSettingCluster", + "storageAccountResourceId": "", + "workspaceResourceId": "" + } + ] + }, + "privateEndpoints": { + "value": [ + { + "privateDnsZoneGroup": { + "privateDnsZoneGroupConfigs": [ + { + "privateDnsZoneResourceId": "" + } + ] + }, + "subnetResourceId": "", + "tags": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + } + ] + }, + "skuName": { + "value": "Balanced_B10" + }, + "tags": { + "value": { + "Environment": "Non-Prod", + "hidden-title": "This is visible in the resource name", + "Role": "DeploymentValidation" + } + }, + "zones": { + "value": [ + 1, + 2, + 3 + ] + } + } +} +``` + +
+

+ +

+ +via Bicep parameters file + +```bicep-params +using 'br/public:avm/res/cache/redis-enterprise:' + +// Required parameters +param name = 'crewaf001' +// Non-required parameters +param database = { + diagnosticSettings: [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + name: 'customSettingDatabase' + storageAccountResourceId: '' + workspaceResourceId: '' + } + ] + persistence: { + frequency: '1h' + type: 'rdb' + } +} +param diagnosticSettings = [ + { + eventHubAuthorizationRuleResourceId: '' + eventHubName: '' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + name: 'customSettingCluster' + storageAccountResourceId: '' + workspaceResourceId: '' + } +] +param privateEndpoints = [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: '' + } + ] + } + subnetResourceId: '' + tags: { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' + } + } +] +param skuName = 'Balanced_B10' +param tags = { + Environment: 'Non-Prod' + 'hidden-title': 'This is visible in the resource name' + Role: 'DeploymentValidation' +} +param zones = [ + 1 + 2 + 3 +] +``` + +
+

+ +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-name) | string | The name of the cache resource. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`managedIdentities`](#parameter-managedidentities) | object | The managed identity definition for this resource. Required if 'customerManagedKey' is not empty. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`capacity`](#parameter-capacity) | int | The size of the cluster. Only supported on Redis Enterprise SKUs: Enterprise, EnterpriseFlash. Valid values are (2, 4, 6, 8, 10) for Enterprise SKUs and (3, 9) for EnterpriseFlash SKUs. [Learn more](https://learn.microsoft.com/azure/azure-cache-for-redis/cache-best-practices-enterprise-tiers#sharding-and-cpu-utilization). | +| [`customerManagedKey`](#parameter-customermanagedkey) | object | The customer managed key definition to use for the managed service. | +| [`database`](#parameter-database) | object | Database configuration. | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The cluster-level diagnostic settings of the service. | +| [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. | +| [`highAvailability`](#parameter-highavailability) | string | Specifies whether to enable data replication for high availability. Used only with Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. HIGH AVAILABILITY IS A PARAMETER USED FOR A PREVIEW FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-high-availability) FOR CLARIFICATION. | +| [`location`](#parameter-location) | string | Location for all resources. | +| [`lock`](#parameter-lock) | object | The lock settings of the service. | +| [`minimumTlsVersion`](#parameter-minimumtlsversion) | string | The minimum TLS version for the Redis cluster to support. | +| [`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. | +| [`skuName`](#parameter-skuname) | string | The type of cluster to deploy. Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized ARE IN PREVIEW, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-overview#tiers-and-skus-at-a-glance) FOR CLARIFICATION. | +| [`tags`](#parameter-tags) | object | Tags of the resource. | +| [`zones`](#parameter-zones) | array | The Availability Zones to place the resources in. Currently only supported on Enterprise and EnterpriseFlash SKUs. | + +### Parameter: `name` + +The name of the cache resource. + +- Required: Yes +- Type: string + +### Parameter: `managedIdentities` + +The managed identity definition for this resource. Required if 'customerManagedKey' is not empty. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`userAssignedResourceIds`](#parameter-managedidentitiesuserassignedresourceids) | array | The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. | + +### Parameter: `managedIdentities.userAssignedResourceIds` + +The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption. + +- Required: No +- Type: array + +### Parameter: `capacity` + +The size of the cluster. Only supported on Redis Enterprise SKUs: Enterprise, EnterpriseFlash. Valid values are (2, 4, 6, 8, 10) for Enterprise SKUs and (3, 9) for EnterpriseFlash SKUs. [Learn more](https://learn.microsoft.com/azure/azure-cache-for-redis/cache-best-practices-enterprise-tiers#sharding-and-cpu-utilization). + +- Required: No +- Type: int +- Default: `2` +- Allowed: + ```Bicep + [ + 2 + 3 + 4 + 6 + 8 + 9 + 10 + ] + ``` + +### Parameter: `customerManagedKey` + +The customer managed key definition to use for the managed service. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyName`](#parameter-customermanagedkeykeyname) | string | The name of the customer managed key to use for encryption. | +| [`keyVaultResourceId`](#parameter-customermanagedkeykeyvaultresourceid) | string | The resource ID of a key vault to reference a customer managed key for encryption from. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVersion`](#parameter-customermanagedkeykeyversion) | string | The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time. | +| [`userAssignedIdentityResourceId`](#parameter-customermanagedkeyuserassignedidentityresourceid) | string | User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. | + +### Parameter: `customerManagedKey.keyName` + +The name of the customer managed key to use for encryption. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.keyVaultResourceId` + +The resource ID of a key vault to reference a customer managed key for encryption from. + +- Required: Yes +- Type: string + +### Parameter: `customerManagedKey.keyVersion` + +The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time. + +- Required: No +- Type: string + +### Parameter: `customerManagedKey.userAssignedIdentityResourceId` + +User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use. + +- Required: No +- Type: string + +### Parameter: `database` + +Database configuration. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessKeysAuthentication`](#parameter-databaseaccesskeysauthentication) | string | Allow authentication via access keys. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication#disable-access-key-authentication-on-your-cache) FOR CLARIFICATION. | +| [`accessPolicyAssignments`](#parameter-databaseaccesspolicyassignments) | array | Access policy assignments for Microsoft Entra authentication. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication) FOR CLARIFICATION. | +| [`clientProtocol`](#parameter-databaseclientprotocol) | string | Specifies whether Redis clients can connect using TLS-encrypted or plaintext Redis protocols. | +| [`clusteringPolicy`](#parameter-databaseclusteringpolicy) | string | Redis clustering policy. [Learn more](https://aka.ms/redis/enterprise/clustering). | +| [`deferUpgrade`](#parameter-databasedeferupgrade) | string | Specifies whether to defer future Redis major version upgrades by up to 90 days. [Learn more](https://aka.ms/redisversionupgrade#defer-upgrades). | +| [`diagnosticSettings`](#parameter-databasediagnosticsettings) | array | The database-level diagnostic settings of the service. | +| [`evictionPolicy`](#parameter-databaseevictionpolicy) | string | Specifies the eviction policy for the Redis resource. | +| [`geoReplication`](#parameter-databasegeoreplication) | object | The active geo-replication settings of the service. All caches within a geo-replication group must have the same configuration. | +| [`modules`](#parameter-databasemodules) | array | Redis modules to enable. Restrictions may apply based on SKU and configuration. [Learn more](https://aka.ms/redis/enterprise/modules). | +| [`name`](#parameter-databasename) | string | Name of the database. | +| [`persistence`](#parameter-databasepersistence) | object | The persistence settings of the service. | +| [`port`](#parameter-databaseport) | int | TCP port of the database endpoint. | +| [`secretsExportConfiguration`](#parameter-databasesecretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | + +### Parameter: `database.accessKeysAuthentication` + +Allow authentication via access keys. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication#disable-access-key-authentication-on-your-cache) FOR CLARIFICATION. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `database.accessPolicyAssignments` + +Access policy assignments for Microsoft Entra authentication. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication) FOR CLARIFICATION. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`userObjectId`](#parameter-databaseaccesspolicyassignmentsuserobjectid) | string | Object ID to which the access policy will be assigned. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessPolicyName`](#parameter-databaseaccesspolicyassignmentsaccesspolicyname) | string | Name of the access policy to be assigned. The current only allowed name is 'default'. | +| [`name`](#parameter-databaseaccesspolicyassignmentsname) | string | Name of the access policy assignment. | + +### Parameter: `database.accessPolicyAssignments.userObjectId` + +Object ID to which the access policy will be assigned. + +- Required: Yes +- Type: string + +### Parameter: `database.accessPolicyAssignments.accessPolicyName` + +Name of the access policy to be assigned. The current only allowed name is 'default'. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'default' + ] + ``` + +### Parameter: `database.accessPolicyAssignments.name` + +Name of the access policy assignment. + +- Required: No +- Type: string + +### Parameter: `database.clientProtocol` + +Specifies whether Redis clients can connect using TLS-encrypted or plaintext Redis protocols. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Encrypted' + 'Plaintext' + ] + ``` + +### Parameter: `database.clusteringPolicy` + +Redis clustering policy. [Learn more](https://aka.ms/redis/enterprise/clustering). + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'EnterpriseCluster' + 'OSSCluster' + ] + ``` + +### Parameter: `database.deferUpgrade` + +Specifies whether to defer future Redis major version upgrades by up to 90 days. [Learn more](https://aka.ms/redisversionupgrade#defer-upgrades). + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Deferred' + 'NotDeferred' + ] + ``` + +### Parameter: `database.diagnosticSettings` + +The database-level diagnostic settings of the service. + +- Required: No +- Type: array + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`eventHubAuthorizationRuleResourceId`](#parameter-databasediagnosticsettingseventhubauthorizationruleresourceid) | 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-databasediagnosticsettingseventhubname) | 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-databasediagnosticsettingsloganalyticsdestinationtype) | 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-databasediagnosticsettingslogcategoriesandgroups) | 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-databasediagnosticsettingsmarketplacepartnerresourceid) | string | The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs. | +| [`name`](#parameter-databasediagnosticsettingsname) | string | The name of diagnostic setting. | +| [`storageAccountResourceId`](#parameter-databasediagnosticsettingsstorageaccountresourceid) | 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-databasediagnosticsettingsworkspaceresourceid) | 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: `database.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: `database.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: `database.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: `database.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-databasediagnosticsettingslogcategoriesandgroupscategory) | 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-databasediagnosticsettingslogcategoriesandgroupscategorygroup) | 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-databasediagnosticsettingslogcategoriesandgroupsenabled) | bool | Enable or disable the category explicitly. Default is `true`. | + +### Parameter: `database.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: `database.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: `database.diagnosticSettings.logCategoriesAndGroups.enabled` + +Enable or disable the category explicitly. Default is `true`. + +- Required: No +- Type: bool + +### Parameter: `database.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: `database.diagnosticSettings.name` + +The name of diagnostic setting. + +- Required: No +- Type: string + +### Parameter: `database.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: `database.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: `database.evictionPolicy` + +Specifies the eviction policy for the Redis resource. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'AllKeysLFU' + 'AllKeysLRU' + 'AllKeysRandom' + 'NoEviction' + 'VolatileLFU' + 'VolatileLRU' + 'VolatileRandom' + 'VolatileTTL' + ] + ``` + +### Parameter: `database.geoReplication` + +The active geo-replication settings of the service. All caches within a geo-replication group must have the same configuration. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupNickname`](#parameter-databasegeoreplicationgroupnickname) | string | The name of the geo-replication group. | +| [`linkedDatabases`](#parameter-databasegeoreplicationlinkeddatabases) | array | List of database resources to link with this database, including itself. | + +### Parameter: `database.geoReplication.groupNickname` + +The name of the geo-replication group. + +- Required: Yes +- Type: string + +### Parameter: `database.geoReplication.linkedDatabases` + +List of database resources to link with this database, including itself. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`id`](#parameter-databasegeoreplicationlinkeddatabasesid) | string | Resource ID of linked database. Should be in the form: `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cache/redisEnterprise/{redisName}/databases/default`. | + +### Parameter: `database.geoReplication.linkedDatabases.id` + +Resource ID of linked database. Should be in the form: `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cache/redisEnterprise/{redisName}/databases/default`. + +- Required: Yes +- Type: string + +### Parameter: `database.modules` + +Redis modules to enable. Restrictions may apply based on SKU and configuration. [Learn more](https://aka.ms/redis/enterprise/modules). + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-databasemodulesname) | string | The name of the module. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`args`](#parameter-databasemodulesargs) | string | Additional module arguments. | + +### Parameter: `database.modules.name` + +The name of the module. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'RedisBloom' + 'RediSearch' + 'RedisJSON' + 'RedisTimeSeries' + ] + ``` + +### Parameter: `database.modules.args` + +Additional module arguments. + +- Required: No +- Type: string + +### Parameter: `database.name` + +Name of the database. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'default' + ] + ``` + +### Parameter: `database.persistence` + +The persistence settings of the service. + +- Required: No +- Type: object + +### Parameter: `database.port` + +TCP port of the database endpoint. + +- Required: No +- Type: int +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `database.secretsExportConfiguration` + +Key vault reference and secret settings for the module's secrets export. + +- Required: No +- Type: object +- MinValue: 10000 +- MaxValue: 10000 + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`keyVaultResourceId`](#parameter-databasesecretsexportconfigurationkeyvaultresourceid) | string | The resource ID of the key vault where to store the secrets of this module. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`primaryAccessKeyName`](#parameter-databasesecretsexportconfigurationprimaryaccesskeyname) | string | The primaryAccessKey secret name to create. | +| [`primaryConnectionStringName`](#parameter-databasesecretsexportconfigurationprimaryconnectionstringname) | string | The primaryConnectionString secret name to create. | +| [`primaryStackExchangeRedisConnectionStringName`](#parameter-databasesecretsexportconfigurationprimarystackexchangeredisconnectionstringname) | string | The primaryStackExchangeRedisConnectionString secret name to create. | +| [`secondaryAccessKeyName`](#parameter-databasesecretsexportconfigurationsecondaryaccesskeyname) | string | The secondaryAccessKey secret name to create. | +| [`secondaryConnectionStringName`](#parameter-databasesecretsexportconfigurationsecondaryconnectionstringname) | string | The secondaryConnectionString secret name to create. | +| [`secondaryStackExchangeRedisConnectionStringName`](#parameter-databasesecretsexportconfigurationsecondarystackexchangeredisconnectionstringname) | string | The secondaryStackExchangeRedisConnectionString secret name to create. | + +### Parameter: `database.secretsExportConfiguration.keyVaultResourceId` + +The resource ID of the key vault where to store the secrets of this module. + +- Required: Yes +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `database.secretsExportConfiguration.primaryAccessKeyName` + +The primaryAccessKey secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `database.secretsExportConfiguration.primaryConnectionStringName` + +The primaryConnectionString secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `database.secretsExportConfiguration.primaryStackExchangeRedisConnectionStringName` + +The primaryStackExchangeRedisConnectionString secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `database.secretsExportConfiguration.secondaryAccessKeyName` + +The secondaryAccessKey secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `database.secretsExportConfiguration.secondaryConnectionStringName` + +The secondaryConnectionString secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `database.secretsExportConfiguration.secondaryStackExchangeRedisConnectionStringName` + +The secondaryStackExchangeRedisConnectionString secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `diagnosticSettings` + +The cluster-level 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. | +| [`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.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: `highAvailability` + +Specifies whether to enable data replication for high availability. Used only with Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. HIGH AVAILABILITY IS A PARAMETER USED FOR A PREVIEW FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-high-availability) FOR CLARIFICATION. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `location` + +Location for all resources. + +- Required: No +- Type: string +- Default: `[resourceGroup().location]` + +### Parameter: `lock` + +The lock settings of the service. + +- Required: No +- Type: object + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`kind`](#parameter-lockkind) | string | Specify the type of lock. | +| [`name`](#parameter-lockname) | string | Specify the name of lock. | + +### Parameter: `lock.kind` + +Specify the type of lock. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'CanNotDelete' + 'None' + 'ReadOnly' + ] + ``` + +### Parameter: `lock.name` + +Specify the name of lock. + +- Required: No +- Type: string + +### Parameter: `minimumTlsVersion` + +The minimum TLS version for the Redis cluster to support. + +- Required: No +- Type: string +- Default: `'1.2'` +- Allowed: + ```Bicep + [ + '1.2' + ] + ``` + +### 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. | +| [`resourceGroupResourceId`](#parameter-privateendpointsresourcegroupresourceid) | string | The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used. | +| [`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" for a Key Vault Private Endpoint. | +| [`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 | +| :-- | :-- | :-- | +| [`ipAddresses`](#parameter-privateendpointscustomdnsconfigsipaddresses) | array | A list of private IP addresses of the private endpoint. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`fqdn`](#parameter-privateendpointscustomdnsconfigsfqdn) | string | FQDN that resolves to private endpoint IP address. | + +### Parameter: `privateEndpoints.customDnsConfigs.ipAddresses` + +A list of private IP addresses of the private endpoint. + +- Required: Yes +- Type: array + +### Parameter: `privateEndpoints.customDnsConfigs.fqdn` + +FQDN that resolves to private endpoint IP address. + +- Required: No +- Type: string + +### 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.resourceGroupResourceId` + +The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used. + +- 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'` + +**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" for a Key Vault Private Endpoint. + +- 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'` + - `'Redis Cache Contributor'` + - `'Role Based Access Control Administrator'` + - `'User Access Administrator'` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`principalId`](#parameter-roleassignmentsprincipalid) | string | The principal ID of the principal (user/group/identity) to assign the role to. | +| [`roleDefinitionIdOrName`](#parameter-roleassignmentsroledefinitionidorname) | string | The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`condition`](#parameter-roleassignmentscondition) | string | The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". | +| [`conditionVersion`](#parameter-roleassignmentsconditionversion) | string | Version of the condition. | +| [`delegatedManagedIdentityResourceId`](#parameter-roleassignmentsdelegatedmanagedidentityresourceid) | string | The Resource Id of the delegated managed identity resource. | +| [`description`](#parameter-roleassignmentsdescription) | string | The description of the role assignment. | +| [`name`](#parameter-roleassignmentsname) | string | The name (as GUID) of the role assignment. If not provided, a GUID will be generated. | +| [`principalType`](#parameter-roleassignmentsprincipaltype) | string | The principal type of the assigned principal ID. | + +### Parameter: `roleAssignments.principalId` + +The principal ID of the principal (user/group/identity) to assign the role to. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.roleDefinitionIdOrName` + +The role to assign. You can provide either the display name of the role definition, the role definition GUID, or its fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11'. + +- Required: Yes +- Type: string + +### Parameter: `roleAssignments.condition` + +The conditions on the role assignment. This limits the resources it can be assigned to. e.g.: @Resource[Microsoft.Storage/storageAccounts/blobServices/containers:ContainerName] StringEqualsIgnoreCase "foo_storage_container". + +- Required: No +- Type: string + +### Parameter: `roleAssignments.conditionVersion` + +Version of the condition. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + '2.0' + ] + ``` + +### Parameter: `roleAssignments.delegatedManagedIdentityResourceId` + +The Resource Id of the delegated managed identity resource. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.description` + +The description of the role assignment. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.name` + +The name (as GUID) of the role assignment. If not provided, a GUID will be generated. + +- Required: No +- Type: string + +### Parameter: `roleAssignments.principalType` + +The principal type of the assigned principal ID. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'Device' + 'ForeignGroup' + 'Group' + 'ServicePrincipal' + 'User' + ] + ``` + +### Parameter: `skuName` + +The type of cluster to deploy. Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized ARE IN PREVIEW, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-overview#tiers-and-skus-at-a-glance) FOR CLARIFICATION. + +- Required: No +- Type: string +- Default: `'Enterprise_E5'` +- Allowed: + ```Bicep + [ + 'Balanced_B0' + 'Balanced_B1' + 'Balanced_B10' + 'Balanced_B100' + 'Balanced_B1000' + 'Balanced_B150' + 'Balanced_B20' + 'Balanced_B250' + 'Balanced_B3' + 'Balanced_B350' + 'Balanced_B5' + 'Balanced_B50' + 'Balanced_B500' + 'Balanced_B700' + 'ComputeOptimized_X10' + 'ComputeOptimized_X100' + 'ComputeOptimized_X150' + 'ComputeOptimized_X20' + 'ComputeOptimized_X250' + 'ComputeOptimized_X3' + 'ComputeOptimized_X350' + 'ComputeOptimized_X5' + 'ComputeOptimized_X50' + 'ComputeOptimized_X500' + 'ComputeOptimized_X700' + 'Enterprise_E1' + 'Enterprise_E10' + 'Enterprise_E100' + 'Enterprise_E20' + 'Enterprise_E200' + 'Enterprise_E400' + 'Enterprise_E5' + 'Enterprise_E50' + 'EnterpriseFlash_F1500' + 'EnterpriseFlash_F300' + 'EnterpriseFlash_F700' + 'FlashOptimized_A1000' + 'FlashOptimized_A1500' + 'FlashOptimized_A2000' + 'FlashOptimized_A250' + 'FlashOptimized_A4500' + 'FlashOptimized_A500' + 'FlashOptimized_A700' + 'MemoryOptimized_M10' + 'MemoryOptimized_M100' + 'MemoryOptimized_M1000' + 'MemoryOptimized_M150' + 'MemoryOptimized_M1500' + 'MemoryOptimized_M20' + 'MemoryOptimized_M2000' + 'MemoryOptimized_M250' + 'MemoryOptimized_M350' + 'MemoryOptimized_M50' + 'MemoryOptimized_M500' + 'MemoryOptimized_M700' + ] + ``` + +### Parameter: `tags` + +Tags of the resource. + +- Required: No +- Type: object + +### Parameter: `zones` + +The Availability Zones to place the resources in. Currently only supported on Enterprise and EnterpriseFlash SKUs. + +- Required: No +- Type: array +- Default: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` +- Allowed: + ```Bicep + [ + 1 + 2 + 3 + ] + ``` + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `databaseName` | string | The name of the Redis database. | +| `databaseResourceId` | string | The resource ID of the database. | +| `endpoint` | string | The Redis endpoint. | +| `exportedSecrets` | | A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name. | +| `location` | string | The location the resource was deployed into. | +| `name` | string | The name of the Redis cluster. | +| `privateEndpoints` | array | The private endpoints of the Redis resource. | +| `resourceGroupName` | string | The name of the resource group the Redis resource was created in. | +| `resourceId` | string | The resource ID of the Redis cluster. | + +## 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.10.1` | Remote reference | +| `br/public:avm/utl/types/avm-common-types:0.5.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/cache/redis-enterprise/database/README.md b/avm/res/cache/redis-enterprise/database/README.md new file mode 100644 index 0000000000..28382a40a4 --- /dev/null +++ b/avm/res/cache/redis-enterprise/database/README.md @@ -0,0 +1,521 @@ +# Redis database `[Microsoft.Cache/redisEnterprise/databases]` + +This module deploys a Redis database in a Redis Enterprise or Azure Managed Redis (Preview) cluster. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) +- [Cross-referenced modules](#Cross-referenced-modules) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Cache/redisEnterprise/databases` | [2024-09-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cache/2024-09-01-preview/redisEnterprise/databases) | +| `Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments` | [2024-09-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cache/2024-09-01-preview/redisEnterprise/databases/accessPolicyAssignments) | +| `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) | + +## Parameters + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`redisClusterName`](#parameter-redisclustername) | string | The name of the parent Redis Enterprise or Azure Managed Redis (Preview) resource. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessKeysAuthentication`](#parameter-accesskeysauthentication) | string | Allow authentication via access keys. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication#disable-access-key-authentication-on-your-cache) FOR CLARIFICATION. | +| [`accessPolicyAssignments`](#parameter-accesspolicyassignments) | array | Access policy assignments for Microsoft Entra authentication. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication) FOR CLARIFICATION. | +| [`clientProtocol`](#parameter-clientprotocol) | string | Specifies whether Redis clients can connect using TLS-encrypted or plaintext Redis protocols. | +| [`clusteringPolicy`](#parameter-clusteringpolicy) | string | Redis clustering policy. [Learn more](https://aka.ms/redis/enterprise/clustering). | +| [`deferUpgrade`](#parameter-deferupgrade) | string | Specifies whether to defer future Redis major version upgrades by up to 90 days. [Learn more](https://aka.ms/redisversionupgrade#defer-upgrades). | +| [`diagnosticSettings`](#parameter-diagnosticsettings) | array | The database-level diagnostic settings of the service. | +| [`evictionPolicy`](#parameter-evictionpolicy) | string | Specifies the eviction policy for the Redis resource. | +| [`geoReplication`](#parameter-georeplication) | object | The active geo-replication settings of the service. All caches within a geo-replication group must have the same configuration. | +| [`modules`](#parameter-modules) | array | Redis modules to enable. Restrictions may apply based on SKU and configuration. [Learn more](https://aka.ms/redis/enterprise/modules). | +| [`name`](#parameter-name) | string | Name of the database. | +| [`persistence`](#parameter-persistence) | object | The persistence settings of the service. | +| [`port`](#parameter-port) | int | TCP port of the database endpoint. | +| [`secretsExportConfiguration`](#parameter-secretsexportconfiguration) | object | Key vault reference and secret settings for the module's secrets export. | + +### Parameter: `redisClusterName` + +The name of the parent Redis Enterprise or Azure Managed Redis (Preview) resource. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `accessKeysAuthentication` + +Allow authentication via access keys. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication#disable-access-key-authentication-on-your-cache) FOR CLARIFICATION. + +- Required: No +- Type: string +- Default: `'Enabled'` +- Allowed: + ```Bicep + [ + 'Disabled' + 'Enabled' + ] + ``` + +### Parameter: `accessPolicyAssignments` + +Access policy assignments for Microsoft Entra authentication. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication) FOR CLARIFICATION. + +- Required: No +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`userObjectId`](#parameter-accesspolicyassignmentsuserobjectid) | string | Object ID to which the access policy will be assigned. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessPolicyName`](#parameter-accesspolicyassignmentsaccesspolicyname) | string | Name of the access policy to be assigned. The current only allowed name is 'default'. | +| [`name`](#parameter-accesspolicyassignmentsname) | string | Name of the access policy assignment. | + +### Parameter: `accessPolicyAssignments.userObjectId` + +Object ID to which the access policy will be assigned. + +- Required: Yes +- Type: string + +### Parameter: `accessPolicyAssignments.accessPolicyName` + +Name of the access policy to be assigned. The current only allowed name is 'default'. + +- Required: No +- Type: string +- Allowed: + ```Bicep + [ + 'default' + ] + ``` + +### Parameter: `accessPolicyAssignments.name` + +Name of the access policy assignment. + +- Required: No +- Type: string + +### Parameter: `clientProtocol` + +Specifies whether Redis clients can connect using TLS-encrypted or plaintext Redis protocols. + +- Required: No +- Type: string +- Default: `'Encrypted'` +- Allowed: + ```Bicep + [ + 'Encrypted' + 'Plaintext' + ] + ``` + +### Parameter: `clusteringPolicy` + +Redis clustering policy. [Learn more](https://aka.ms/redis/enterprise/clustering). + +- Required: No +- Type: string +- Default: `'OSSCluster'` +- Allowed: + ```Bicep + [ + 'EnterpriseCluster' + 'OSSCluster' + ] + ``` + +### Parameter: `deferUpgrade` + +Specifies whether to defer future Redis major version upgrades by up to 90 days. [Learn more](https://aka.ms/redisversionupgrade#defer-upgrades). + +- Required: No +- Type: string +- Default: `'NotDeferred'` +- Allowed: + ```Bicep + [ + 'Deferred' + 'NotDeferred' + ] + ``` + +### Parameter: `diagnosticSettings` + +The database-level 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. | +| [`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.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: `evictionPolicy` + +Specifies the eviction policy for the Redis resource. + +- Required: No +- Type: string +- Default: `'VolatileLRU'` +- Allowed: + ```Bicep + [ + 'AllKeysLFU' + 'AllKeysLRU' + 'AllKeysRandom' + 'NoEviction' + 'VolatileLFU' + 'VolatileLRU' + 'VolatileRandom' + 'VolatileTTL' + ] + ``` + +### Parameter: `geoReplication` + +The active geo-replication settings of the service. All caches within a geo-replication group must have the same configuration. + +- Required: No +- Type: object + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`groupNickname`](#parameter-georeplicationgroupnickname) | string | The name of the geo-replication group. | +| [`linkedDatabases`](#parameter-georeplicationlinkeddatabases) | array | List of database resources to link with this database, including itself. | + +### Parameter: `geoReplication.groupNickname` + +The name of the geo-replication group. + +- Required: Yes +- Type: string + +### Parameter: `geoReplication.linkedDatabases` + +List of database resources to link with this database, including itself. + +- Required: Yes +- Type: array + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`id`](#parameter-georeplicationlinkeddatabasesid) | string | Resource ID of linked database. Should be in the form: `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cache/redisEnterprise/{redisName}/databases/default`. | + +### Parameter: `geoReplication.linkedDatabases.id` + +Resource ID of linked database. Should be in the form: `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cache/redisEnterprise/{redisName}/databases/default`. + +- Required: Yes +- Type: string + +### Parameter: `modules` + +Redis modules to enable. Restrictions may apply based on SKU and configuration. [Learn more](https://aka.ms/redis/enterprise/modules). + +- Required: No +- Type: array +- Default: `[]` + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`name`](#parameter-modulesname) | string | The name of the module. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`args`](#parameter-modulesargs) | string | Additional module arguments. | + +### Parameter: `modules.name` + +The name of the module. + +- Required: Yes +- Type: string +- Allowed: + ```Bicep + [ + 'RedisBloom' + 'RediSearch' + 'RedisJSON' + 'RedisTimeSeries' + ] + ``` + +### Parameter: `modules.args` + +Additional module arguments. + +- Required: No +- Type: string + +### Parameter: `name` + +Name of the database. + +- Required: No +- Type: string +- Default: `'default'` +- Allowed: + ```Bicep + [ + 'default' + ] + ``` + +### Parameter: `persistence` + +The persistence settings of the service. + +- Required: No +- Type: object +- Default: + ```Bicep + { + type: 'disabled' + } + ``` + +### Parameter: `port` + +TCP port of the database endpoint. + +- Required: No +- Type: int +- Default: `10000` +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `secretsExportConfiguration` + +Key vault reference and secret settings for the module's secrets export. + +- Required: No +- Type: object +- MinValue: 10000 +- MaxValue: 10000 + +**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 | +| :-- | :-- | :-- | +| [`primaryAccessKeyName`](#parameter-secretsexportconfigurationprimaryaccesskeyname) | string | The primaryAccessKey secret name to create. | +| [`primaryConnectionStringName`](#parameter-secretsexportconfigurationprimaryconnectionstringname) | string | The primaryConnectionString secret name to create. | +| [`primaryStackExchangeRedisConnectionStringName`](#parameter-secretsexportconfigurationprimarystackexchangeredisconnectionstringname) | string | The primaryStackExchangeRedisConnectionString secret name to create. | +| [`secondaryAccessKeyName`](#parameter-secretsexportconfigurationsecondaryaccesskeyname) | string | The secondaryAccessKey secret name to create. | +| [`secondaryConnectionStringName`](#parameter-secretsexportconfigurationsecondaryconnectionstringname) | string | The secondaryConnectionString secret name to create. | +| [`secondaryStackExchangeRedisConnectionStringName`](#parameter-secretsexportconfigurationsecondarystackexchangeredisconnectionstringname) | string | The secondaryStackExchangeRedisConnectionString secret name to create. | + +### Parameter: `secretsExportConfiguration.keyVaultResourceId` + +The resource ID of the key vault where to store the secrets of this module. + +- Required: Yes +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `secretsExportConfiguration.primaryAccessKeyName` + +The primaryAccessKey secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `secretsExportConfiguration.primaryConnectionStringName` + +The primaryConnectionString secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `secretsExportConfiguration.primaryStackExchangeRedisConnectionStringName` + +The primaryStackExchangeRedisConnectionString secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `secretsExportConfiguration.secondaryAccessKeyName` + +The secondaryAccessKey secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `secretsExportConfiguration.secondaryConnectionStringName` + +The secondaryConnectionString secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +### Parameter: `secretsExportConfiguration.secondaryStackExchangeRedisConnectionStringName` + +The secondaryStackExchangeRedisConnectionString secret name to create. + +- Required: No +- Type: string +- MinValue: 10000 +- MaxValue: 10000 + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `endpoint` | string | The Redis endpoint. | +| `exportedSecrets` | | A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name. | +| `name` | string | The name of the Redis database. | +| `port` | int | The Redis database port. | +| `resourceGroupName` | string | The name of the resource group the Redis resource was created in. | +| `resourceId` | string | The resource ID of the database. | + +## 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/utl/types/avm-common-types:0.5.1` | Remote reference | diff --git a/avm/res/cache/redis-enterprise/database/access-policy-assignment/README.md b/avm/res/cache/redis-enterprise/database/access-policy-assignment/README.md new file mode 100644 index 0000000000..dea6191c23 --- /dev/null +++ b/avm/res/cache/redis-enterprise/database/access-policy-assignment/README.md @@ -0,0 +1,88 @@ +# Azure Managed Redis (Preview) Database Access Policy Assignment `[Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments]` + +This module deploys an access policy assignment for an Azure Managed Redis (Preview) database. + +## Navigation + +- [Resource Types](#Resource-Types) +- [Parameters](#Parameters) +- [Outputs](#Outputs) + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments` | [2024-09-01-preview](https://learn.microsoft.com/en-us/azure/templates/Microsoft.Cache/2024-09-01-preview/redisEnterprise/databases/accessPolicyAssignments) | + +## Parameters + +**Required parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`userObjectId`](#parameter-userobjectid) | string | Object ID to which the access policy will be assigned. | + +**Conditional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`clusterName`](#parameter-clustername) | string | The name of the grandparent Azure Managed Redis (Preview) cluster. Required if the template is used in a standalone deployment. | +| [`databaseName`](#parameter-databasename) | string | The name of the parent Azure Managed Redis (Preview) database. Required if the template is used in a standalone deployment. | + +**Optional parameters** + +| Parameter | Type | Description | +| :-- | :-- | :-- | +| [`accessPolicyName`](#parameter-accesspolicyname) | string | Name of the access policy to be assigned. | +| [`name`](#parameter-name) | string | Name of the access policy assignment. | + +### Parameter: `userObjectId` + +Object ID to which the access policy will be assigned. + +- Required: Yes +- Type: string + +### Parameter: `clusterName` + +The name of the grandparent Azure Managed Redis (Preview) cluster. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `databaseName` + +The name of the parent Azure Managed Redis (Preview) database. Required if the template is used in a standalone deployment. + +- Required: Yes +- Type: string + +### Parameter: `accessPolicyName` + +Name of the access policy to be assigned. + +- Required: No +- Type: string +- Default: `'default'` +- Allowed: + ```Bicep + [ + 'default' + ] + ``` + +### Parameter: `name` + +Name of the access policy assignment. + +- Required: No +- Type: string + +## Outputs + +| Output | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The name of the access policy assignment. | +| `resourceGroupName` | string | The resource group the access policy assignment was deployed into. | +| `resourceId` | string | The resource ID of the access policy assignment. | +| `userObjectId` | string | The object ID of the user associated with the access policy. | diff --git a/avm/res/cache/redis-enterprise/database/access-policy-assignment/main.bicep b/avm/res/cache/redis-enterprise/database/access-policy-assignment/main.bicep new file mode 100644 index 0000000000..87c5f1905e --- /dev/null +++ b/avm/res/cache/redis-enterprise/database/access-policy-assignment/main.bicep @@ -0,0 +1,51 @@ +metadata name = 'Azure Managed Redis (Preview) Database Access Policy Assignment' +metadata description = 'This module deploys an access policy assignment for an Azure Managed Redis (Preview) database.' + +@description('Optional. Name of the access policy assignment.') +param name string? + +@description('Required. Object ID to which the access policy will be assigned.') +param userObjectId string + +@description('Conditional. The name of the grandparent Azure Managed Redis (Preview) cluster. Required if the template is used in a standalone deployment.') +param clusterName string + +@description('Conditional. The name of the parent Azure Managed Redis (Preview) database. Required if the template is used in a standalone deployment.') +param databaseName string + +@allowed([ + 'default' +]) +@description('Optional. Name of the access policy to be assigned.') +param accessPolicyName string = 'default' + +resource redisCluster 'Microsoft.Cache/redisEnterprise@2024-09-01-preview' existing = { + name: clusterName + + resource database 'databases@2024-09-01-preview' existing = { + name: databaseName + } +} + +resource accessPolicyAssignment 'Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments@2024-09-01-preview' = { + name: name ?? userObjectId + parent: redisCluster::database + properties: { + accessPolicyName: accessPolicyName + user: { + objectId: userObjectId + } + } +} + +@description('The name of the access policy assignment.') +output name string = accessPolicyAssignment.name + +@description('The resource ID of the access policy assignment.') +output resourceId string = accessPolicyAssignment.id + +@description('The resource group the access policy assignment was deployed into.') +output resourceGroupName string = resourceGroup().name + +@description('The object ID of the user associated with the access policy.') +output userObjectId string = accessPolicyAssignment.properties.user.objectId diff --git a/avm/res/cache/redis-enterprise/database/access-policy-assignment/main.json b/avm/res/cache/redis-enterprise/database/access-policy-assignment/main.json new file mode 100644 index 0000000000..3e7603c8b8 --- /dev/null +++ b/avm/res/cache/redis-enterprise/database/access-policy-assignment/main.json @@ -0,0 +1,106 @@ +{ + "$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.33.93.31351", + "templateHash": "6473026260124919331" + }, + "name": "Azure Managed Redis (Preview) Database Access Policy Assignment", + "description": "This module deploys an access policy assignment for an Azure Managed Redis (Preview) database." + }, + "parameters": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the access policy assignment." + } + }, + "userObjectId": { + "type": "string", + "metadata": { + "description": "Required. Object ID to which the access policy will be assigned." + } + }, + "clusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the grandparent Azure Managed Redis (Preview) cluster. Required if the template is used in a standalone deployment." + } + }, + "databaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Managed Redis (Preview) database. Required if the template is used in a standalone deployment." + } + }, + "accessPolicyName": { + "type": "string", + "defaultValue": "default", + "allowedValues": [ + "default" + ], + "metadata": { + "description": "Optional. Name of the access policy to be assigned." + } + } + }, + "resources": { + "redisCluster::database": { + "existing": true, + "type": "Microsoft.Cache/redisEnterprise/databases", + "apiVersion": "2024-09-01-preview", + "name": "[format('{0}/{1}', parameters('clusterName'), parameters('databaseName'))]" + }, + "redisCluster": { + "existing": true, + "type": "Microsoft.Cache/redisEnterprise", + "apiVersion": "2024-09-01-preview", + "name": "[parameters('clusterName')]" + }, + "accessPolicyAssignment": { + "type": "Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments", + "apiVersion": "2024-09-01-preview", + "name": "[format('{0}/{1}/{2}', parameters('clusterName'), parameters('databaseName'), coalesce(parameters('name'), parameters('userObjectId')))]", + "properties": { + "accessPolicyName": "[parameters('accessPolicyName')]", + "user": { + "objectId": "[parameters('userObjectId')]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policy assignment." + }, + "value": "[coalesce(parameters('name'), parameters('userObjectId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policy assignment." + }, + "value": "[resourceId('Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments', parameters('clusterName'), parameters('databaseName'), coalesce(parameters('name'), parameters('userObjectId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the access policy assignment was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "userObjectId": { + "type": "string", + "metadata": { + "description": "The object ID of the user associated with the access policy." + }, + "value": "[reference('accessPolicyAssignment').user.objectId]" + } + } +} diff --git a/avm/res/cache/redis-enterprise/database/main.bicep b/avm/res/cache/redis-enterprise/database/main.bicep new file mode 100644 index 0000000000..3a45317109 --- /dev/null +++ b/avm/res/cache/redis-enterprise/database/main.bicep @@ -0,0 +1,329 @@ +metadata name = 'Redis database' +metadata description = 'This module deploys a Redis database in a Redis Enterprise or Azure Managed Redis (Preview) cluster.' + +@description('Conditional. The name of the parent Redis Enterprise or Azure Managed Redis (Preview) resource. Required if the template is used in a standalone deployment.') +param redisClusterName string + +@allowed([ + 'default' +]) +@description('Optional. Name of the database.') +param name string = 'default' + +@allowed([ + 'Enabled' + 'Disabled' +]) +@description('Optional. Allow authentication via access keys. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication#disable-access-key-authentication-on-your-cache) FOR CLARIFICATION.') +param accessKeysAuthentication string = 'Enabled' + +@allowed([ + 'Encrypted' + 'Plaintext' +]) +@description('Optional. Specifies whether Redis clients can connect using TLS-encrypted or plaintext Redis protocols.') +param clientProtocol string = 'Encrypted' + +@allowed([ + 'EnterpriseCluster' + 'OSSCluster' +]) +@description('Optional. Redis clustering policy. [Learn more](https://aka.ms/redis/enterprise/clustering).') +param clusteringPolicy string = 'OSSCluster' + +@allowed([ + 'Deferred' + 'NotDeferred' +]) +@description('Optional. Specifies whether to defer future Redis major version upgrades by up to 90 days. [Learn more](https://aka.ms/redisversionupgrade#defer-upgrades).') +param deferUpgrade string = 'NotDeferred' + +@allowed([ + 'AllKeysLFU' + 'AllKeysLRU' + 'AllKeysRandom' + 'NoEviction' + 'VolatileLFU' + 'VolatileLRU' + 'VolatileRandom' + 'VolatileTTL' +]) +@description('Optional. Specifies the eviction policy for the Redis resource.') +param evictionPolicy string = 'VolatileLRU' + +@description('Optional. The active geo-replication settings of the service. All caches within a geo-replication group must have the same configuration.') +param geoReplication geoReplicationType? + +@description('Optional. Redis modules to enable. Restrictions may apply based on SKU and configuration. [Learn more](https://aka.ms/redis/enterprise/modules).') +param modules moduleType[] = [] + +@description('Optional. TCP port of the database endpoint.') +@minValue(10000) +@maxValue(10000) +param port int = 10000 + +@description('Optional. The persistence settings of the service.') +param persistence persistenceType = { + type: 'disabled' +} + +@description('Optional. Access policy assignments for Microsoft Entra authentication. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication) FOR CLARIFICATION.') +param accessPolicyAssignments accessPolicyAssignmentType[]? + +@description('Optional. Key vault reference and secret settings for the module\'s secrets export.') +param secretsExportConfiguration secretsExportConfigurationType? + +import { diagnosticSettingLogsOnlyType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The database-level diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingLogsOnlyType[]? + +// ============== // +// Resources // +// ============== // + +resource redisCluster 'Microsoft.Cache/redisEnterprise@2024-09-01-preview' existing = { + name: redisClusterName +} + +var clusterSku = redisCluster.sku.name +var isAmr = startsWith(clusterSku, 'Balanced') || startsWith(clusterSku, 'ComputeOptimized') || startsWith( + clusterSku, + 'FlashOptimized' +) || startsWith(clusterSku, 'MemoryOptimized') + +resource redisDatabase 'Microsoft.Cache/redisEnterprise/databases@2024-09-01-preview' = { + parent: redisCluster + name: name + properties: { + accessKeysAuthentication: isAmr ? accessKeysAuthentication : null + clientProtocol: clientProtocol + clusteringPolicy: clusteringPolicy + deferUpgrade: deferUpgrade + evictionPolicy: evictionPolicy + geoReplication: !empty(geoReplication) ? geoReplication : null + modules: modules + port: port + persistence: persistence.type != 'disabled' + ? { + aofEnabled: persistence.type == 'aof' + rdbEnabled: persistence.type == 'rdb' + aofFrequency: persistence.type == 'aof' ? persistence.frequency : null + rdbFrequency: persistence.type == 'rdb' ? persistence.frequency : null + } + : null + } +} + +module database_accessPolicyAssignments 'access-policy-assignment/main.bicep' = [ + for (assignment, index) in (accessPolicyAssignments ?? []): { + name: '${uniqueString(deployment().name)}-redis-apa-${index}' + params: { + name: assignment.name + clusterName: redisCluster.name + databaseName: redisDatabase.name + accessPolicyName: assignment.?accessPolicyName + userObjectId: assignment.userObjectId + } + } +] + +resource database_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 + 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: redisDatabase + } +] + +module secretsExport 'modules/keyVaultExport.bicep' = if (secretsExportConfiguration != null) { + name: '${uniqueString(deployment().name)}-secrets-kv' + scope: resourceGroup( + split(secretsExportConfiguration.?keyVaultResourceId!, '/')[2], + split(secretsExportConfiguration.?keyVaultResourceId!, '/')[4] + ) + params: { + keyVaultName: last(split(secretsExportConfiguration.?keyVaultResourceId!, '/')) + secretsToSet: union( + [], + contains(secretsExportConfiguration!, 'primaryAccessKeyName') + ? [ + { + name: secretsExportConfiguration!.?primaryAccessKeyName + value: redisDatabase.listKeys().primaryKey + } + ] + : [], + contains(secretsExportConfiguration!, 'primaryConnectionStringName') + ? [ + { + name: secretsExportConfiguration!.?primaryConnectionStringName + value: '${redisDatabase.properties.clientProtocol == 'Plaintext' ? 'redis://' : 'rediss://' }:${redisDatabase.listKeys().primaryKey}@${redisCluster.properties.hostName}:${redisDatabase.properties.port}' + } + ] + : [], + contains(secretsExportConfiguration!, 'primaryStackExchangeRedisConnectionStringName') + ? [ + { + name: secretsExportConfiguration!.?primaryStackExchangeRedisConnectionStringName + value: '${redisCluster.properties.hostName}:${redisDatabase.properties.port},password=${redisDatabase.listKeys().primaryKey},ssl=${redisDatabase.properties.clientProtocol == 'Plaintext' ? 'False' : 'True'},abortConnect=False' + } + ] + : [], + contains(secretsExportConfiguration!, 'secondaryAccessKeyName') + ? [ + { + name: secretsExportConfiguration!.?secondaryAccessKeyName + value: redisDatabase.listKeys().secondaryKey + } + ] + : [], + contains(secretsExportConfiguration!, 'secondaryConnectionStringName') + ? [ + { + name: secretsExportConfiguration!.?secondaryConnectionStringName + value: '${redisDatabase.properties.clientProtocol == 'Plaintext' ? 'redis://' : 'rediss://' }:${redisDatabase.listKeys().secondaryKey}@${redisCluster.properties.hostName}:${redisDatabase.properties.port}' + } + ] + : [], + contains(secretsExportConfiguration!, 'secondaryStackExchangeRedisConnectionStringName') + ? [ + { + name: secretsExportConfiguration!.?secondaryStackExchangeRedisConnectionStringName + value: '${redisCluster.properties.hostName}:${redisDatabase.properties.port},password=${redisDatabase.listKeys().secondaryKey},ssl=${redisDatabase.properties.clientProtocol == 'Plaintext' ? 'False' : 'True'},abortConnect=False' + } + ] + : [] + ) + } +} + +// ============ // +// Outputs // +// ============ // + +@description('The name of the Redis database.') +output name string = redisDatabase.name + +@description('The resource ID of the database.') +output resourceId string = redisDatabase.id + +@description('The name of the resource group the Redis resource was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The Redis database port.') +output port int = redisDatabase.properties.port + +@description('The Redis endpoint.') +output endpoint string = '${redisCluster.properties.hostName}:${redisDatabase.properties.port}' + +import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = (secretsExportConfiguration != null) + ? toObject(secretsExport.outputs.secretsSet, secret => last(split(secret.secretResourceId, '/')), secret => secret) + : {} + +// =============== // +// Definitions // +// =============== // + +@export() +type secretsExportConfigurationType = { + @description('Required. The resource ID of the key vault where to store the secrets of this module.') + keyVaultResourceId: string + + @description('Optional. The primaryAccessKey secret name to create.') + primaryAccessKeyName: string? + + @description('Optional. The primaryConnectionString secret name to create.') + primaryConnectionStringName: string? + + @description('Optional. The primaryStackExchangeRedisConnectionString secret name to create.') + primaryStackExchangeRedisConnectionStringName: string? + + @description('Optional. The secondaryAccessKey secret name to create.') + secondaryAccessKeyName: string? + + @description('Optional. The secondaryConnectionString secret name to create.') + secondaryConnectionStringName: string? + + @description('Optional. The secondaryStackExchangeRedisConnectionString secret name to create.') + secondaryStackExchangeRedisConnectionStringName: string? +} + +@export() +type disabledPersistenceType = { + @description('Required. Disabled persistence type.') + type: 'disabled' +} + +@export() +type aofPersistenceType = { + @description('Required. AOF persistence type.') + type: 'aof' + + @description('Required. The frequency at which data is written to disk.') + frequency: '1s' +} + +@export() +type rdbPersistenceType = { + @description('Required. RDB persistence type.') + type: 'rdb' + + @description('Required. The frequency at which an RDB snapshot of the database is created.') + frequency: '1h' | '6h' | '12h' +} + +@export() +@discriminator('type') +type persistenceType = disabledPersistenceType | aofPersistenceType | rdbPersistenceType + +@export() +type moduleType = { + @description('Required. The name of the module.') + name: ('RedisBloom' | 'RedisTimeSeries' | 'RedisJSON' | 'RediSearch') + + @description('Optional. Additional module arguments.') + args: string? +} + +@export() +type geoReplicationType = { + @description('Required. The name of the geo-replication group.') + groupNickname: string + + @description('Required. List of database resources to link with this database, including itself.') + linkedDatabases: linkedDatabaseType[] +} + +@export() +type linkedDatabaseType = { + @description('Required. Resource ID of linked database. Should be in the form: `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cache/redisEnterprise/{redisName}/databases/default`.') + id: string +} + +@export() +type accessPolicyAssignmentType = { + @description('Optional. Name of the access policy assignment.') + name: string? + + @description('Required. Object ID to which the access policy will be assigned.') + userObjectId: string + + @description('Optional. Name of the access policy to be assigned. The current only allowed name is \'default\'.') + accessPolicyName: ('default')? +} diff --git a/avm/res/cache/redis-enterprise/database/main.json b/avm/res/cache/redis-enterprise/database/main.json new file mode 100644 index 0000000000..82a2cc12c4 --- /dev/null +++ b/avm/res/cache/redis-enterprise/database/main.json @@ -0,0 +1,933 @@ +{ + "$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.33.93.31351", + "templateHash": "12094637252334328193" + }, + "name": "Redis database", + "description": "This module deploys a Redis database in a Redis Enterprise or Azure Managed Redis (Preview) cluster." + }, + "definitions": { + "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." + } + }, + "primaryAccessKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryAccessKey secret name to create." + } + }, + "primaryConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryConnectionString secret name to create." + } + }, + "primaryStackExchangeRedisConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryStackExchangeRedisConnectionString secret name to create." + } + }, + "secondaryAccessKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryAccessKey secret name to create." + } + }, + "secondaryConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryConnectionString secret name to create." + } + }, + "secondaryStackExchangeRedisConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryStackExchangeRedisConnectionString secret name to create." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "disabledPersistenceType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "disabled" + ], + "metadata": { + "description": "Required. Disabled persistence type." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "aofPersistenceType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "aof" + ], + "metadata": { + "description": "Required. AOF persistence type." + } + }, + "frequency": { + "type": "string", + "allowedValues": [ + "1s" + ], + "metadata": { + "description": "Required. The frequency at which data is written to disk." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "rdbPersistenceType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "rdb" + ], + "metadata": { + "description": "Required. RDB persistence type." + } + }, + "frequency": { + "type": "string", + "allowedValues": [ + "12h", + "1h", + "6h" + ], + "metadata": { + "description": "Required. The frequency at which an RDB snapshot of the database is created." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "persistenceType": { + "type": "object", + "discriminator": { + "propertyName": "type", + "mapping": { + "disabled": { + "$ref": "#/definitions/disabledPersistenceType" + }, + "aof": { + "$ref": "#/definitions/aofPersistenceType" + }, + "rdb": { + "$ref": "#/definitions/rdbPersistenceType" + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "moduleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "RediSearch", + "RedisBloom", + "RedisJSON", + "RedisTimeSeries" + ], + "metadata": { + "description": "Required. The name of the module." + } + }, + "args": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Additional module arguments." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "geoReplicationType": { + "type": "object", + "properties": { + "groupNickname": { + "type": "string", + "metadata": { + "description": "Required. The name of the geo-replication group." + } + }, + "linkedDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedDatabaseType" + }, + "metadata": { + "description": "Required. List of database resources to link with this database, including itself." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "linkedDatabaseType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of linked database. Should be in the form: `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cache/redisEnterprise/{redisName}/databases/default`." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "accessPolicyAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the access policy assignment." + } + }, + "userObjectId": { + "type": "string", + "metadata": { + "description": "Required. Object ID to which the access policy will be assigned." + } + }, + "accessPolicyName": { + "type": "string", + "allowedValues": [ + "default" + ], + "nullable": true, + "metadata": { + "description": "Optional. Name of the access policy to be assigned. The current only allowed name is 'default'." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "_1.secretSetOutputType": { + "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." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "redisClusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Redis Enterprise or Azure Managed Redis (Preview) resource. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "allowedValues": [ + "default" + ], + "metadata": { + "description": "Optional. Name of the database." + } + }, + "accessKeysAuthentication": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Allow authentication via access keys. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication#disable-access-key-authentication-on-your-cache) FOR CLARIFICATION." + } + }, + "clientProtocol": { + "type": "string", + "defaultValue": "Encrypted", + "allowedValues": [ + "Encrypted", + "Plaintext" + ], + "metadata": { + "description": "Optional. Specifies whether Redis clients can connect using TLS-encrypted or plaintext Redis protocols." + } + }, + "clusteringPolicy": { + "type": "string", + "defaultValue": "OSSCluster", + "allowedValues": [ + "EnterpriseCluster", + "OSSCluster" + ], + "metadata": { + "description": "Optional. Redis clustering policy. [Learn more](https://aka.ms/redis/enterprise/clustering)." + } + }, + "deferUpgrade": { + "type": "string", + "defaultValue": "NotDeferred", + "allowedValues": [ + "Deferred", + "NotDeferred" + ], + "metadata": { + "description": "Optional. Specifies whether to defer future Redis major version upgrades by up to 90 days. [Learn more](https://aka.ms/redisversionupgrade#defer-upgrades)." + } + }, + "evictionPolicy": { + "type": "string", + "defaultValue": "VolatileLRU", + "allowedValues": [ + "AllKeysLFU", + "AllKeysLRU", + "AllKeysRandom", + "NoEviction", + "VolatileLFU", + "VolatileLRU", + "VolatileRandom", + "VolatileTTL" + ], + "metadata": { + "description": "Optional. Specifies the eviction policy for the Redis resource." + } + }, + "geoReplication": { + "$ref": "#/definitions/geoReplicationType", + "nullable": true, + "metadata": { + "description": "Optional. The active geo-replication settings of the service. All caches within a geo-replication group must have the same configuration." + } + }, + "modules": { + "type": "array", + "items": { + "$ref": "#/definitions/moduleType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Redis modules to enable. Restrictions may apply based on SKU and configuration. [Learn more](https://aka.ms/redis/enterprise/modules)." + } + }, + "port": { + "type": "int", + "defaultValue": 10000, + "minValue": 10000, + "maxValue": 10000, + "metadata": { + "description": "Optional. TCP port of the database endpoint." + } + }, + "persistence": { + "$ref": "#/definitions/persistenceType", + "defaultValue": { + "type": "disabled" + }, + "metadata": { + "description": "Optional. The persistence settings of the service." + } + }, + "accessPolicyAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/accessPolicyAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Access policy assignments for Microsoft Entra authentication. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication) FOR CLARIFICATION." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The database-level diagnostic settings of the service." + } + } + }, + "resources": { + "redisCluster": { + "existing": true, + "type": "Microsoft.Cache/redisEnterprise", + "apiVersion": "2024-09-01-preview", + "name": "[parameters('redisClusterName')]" + }, + "redisDatabase": { + "type": "Microsoft.Cache/redisEnterprise/databases", + "apiVersion": "2024-09-01-preview", + "name": "[format('{0}/{1}', parameters('redisClusterName'), parameters('name'))]", + "properties": { + "accessKeysAuthentication": "[if(or(or(or(startsWith(reference('redisCluster', '2024-09-01-preview', 'full').sku.name, 'Balanced'), startsWith(reference('redisCluster', '2024-09-01-preview', 'full').sku.name, 'ComputeOptimized')), startsWith(reference('redisCluster', '2024-09-01-preview', 'full').sku.name, 'FlashOptimized')), startsWith(reference('redisCluster', '2024-09-01-preview', 'full').sku.name, 'MemoryOptimized')), parameters('accessKeysAuthentication'), null())]", + "clientProtocol": "[parameters('clientProtocol')]", + "clusteringPolicy": "[parameters('clusteringPolicy')]", + "deferUpgrade": "[parameters('deferUpgrade')]", + "evictionPolicy": "[parameters('evictionPolicy')]", + "geoReplication": "[if(not(empty(parameters('geoReplication'))), parameters('geoReplication'), null())]", + "modules": "[parameters('modules')]", + "port": "[parameters('port')]", + "persistence": "[if(not(equals(parameters('persistence').type, 'disabled')), createObject('aofEnabled', equals(parameters('persistence').type, 'aof'), 'rdbEnabled', equals(parameters('persistence').type, 'rdb'), 'aofFrequency', if(equals(parameters('persistence').type, 'aof'), parameters('persistence').frequency, null()), 'rdbFrequency', if(equals(parameters('persistence').type, 'rdb'), parameters('persistence').frequency, null())), null())]" + }, + "dependsOn": [ + "redisCluster" + ] + }, + "database_diagnosticSettings": { + "copy": { + "name": "database_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Cache/redisEnterprise/{0}/databases/{1}', parameters('redisClusterName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "redisDatabase" + ] + }, + "database_accessPolicyAssignments": { + "copy": { + "name": "database_accessPolicyAssignments", + "count": "[length(coalesce(parameters('accessPolicyAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-redis-apa-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('accessPolicyAssignments'), createArray())[copyIndex()].name]" + }, + "clusterName": { + "value": "[parameters('redisClusterName')]" + }, + "databaseName": { + "value": "[parameters('name')]" + }, + "accessPolicyName": { + "value": "[tryGet(coalesce(parameters('accessPolicyAssignments'), createArray())[copyIndex()], 'accessPolicyName')]" + }, + "userObjectId": { + "value": "[coalesce(parameters('accessPolicyAssignments'), createArray())[copyIndex()].userObjectId]" + } + }, + "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.33.93.31351", + "templateHash": "6473026260124919331" + }, + "name": "Azure Managed Redis (Preview) Database Access Policy Assignment", + "description": "This module deploys an access policy assignment for an Azure Managed Redis (Preview) database." + }, + "parameters": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the access policy assignment." + } + }, + "userObjectId": { + "type": "string", + "metadata": { + "description": "Required. Object ID to which the access policy will be assigned." + } + }, + "clusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the grandparent Azure Managed Redis (Preview) cluster. Required if the template is used in a standalone deployment." + } + }, + "databaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Managed Redis (Preview) database. Required if the template is used in a standalone deployment." + } + }, + "accessPolicyName": { + "type": "string", + "defaultValue": "default", + "allowedValues": [ + "default" + ], + "metadata": { + "description": "Optional. Name of the access policy to be assigned." + } + } + }, + "resources": { + "redisCluster::database": { + "existing": true, + "type": "Microsoft.Cache/redisEnterprise/databases", + "apiVersion": "2024-09-01-preview", + "name": "[format('{0}/{1}', parameters('clusterName'), parameters('databaseName'))]" + }, + "redisCluster": { + "existing": true, + "type": "Microsoft.Cache/redisEnterprise", + "apiVersion": "2024-09-01-preview", + "name": "[parameters('clusterName')]" + }, + "accessPolicyAssignment": { + "type": "Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments", + "apiVersion": "2024-09-01-preview", + "name": "[format('{0}/{1}/{2}', parameters('clusterName'), parameters('databaseName'), coalesce(parameters('name'), parameters('userObjectId')))]", + "properties": { + "accessPolicyName": "[parameters('accessPolicyName')]", + "user": { + "objectId": "[parameters('userObjectId')]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policy assignment." + }, + "value": "[coalesce(parameters('name'), parameters('userObjectId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policy assignment." + }, + "value": "[resourceId('Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments', parameters('clusterName'), parameters('databaseName'), coalesce(parameters('name'), parameters('userObjectId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the access policy assignment was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "userObjectId": { + "type": "string", + "metadata": { + "description": "The object ID of the user associated with the access policy." + }, + "value": "[reference('accessPolicyAssignment').user.objectId]" + } + } + } + }, + "dependsOn": [ + "redisDatabase" + ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAccessKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAccessKeyName'), 'value', listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'primaryConnectionStringName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryConnectionStringName'), 'value', format('{0}:{1}@{2}:{3}', if(equals(reference('redisDatabase').clientProtocol, 'Plaintext'), 'redis://', 'rediss://'), listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').primaryKey, reference('redisCluster').hostName, reference('redisDatabase').port))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'primaryStackExchangeRedisConnectionStringName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryStackExchangeRedisConnectionStringName'), 'value', format('{0}:{1},password={2},ssl={3},abortConnect=False', reference('redisCluster').hostName, reference('redisDatabase').port, listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').primaryKey, if(equals(reference('redisDatabase').clientProtocol, 'Plaintext'), 'False', 'True')))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAccessKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAccessKeyName'), 'value', listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').secondaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryConnectionStringName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryConnectionStringName'), 'value', format('{0}:{1}@{2}:{3}', if(equals(reference('redisDatabase').clientProtocol, 'Plaintext'), 'redis://', 'rediss://'), listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').secondaryKey, reference('redisCluster').hostName, reference('redisDatabase').port))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryStackExchangeRedisConnectionStringName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryStackExchangeRedisConnectionStringName'), 'value', format('{0}:{1},password={2},ssl={3},abortConnect=False', reference('redisCluster').hostName, reference('redisDatabase').port, listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').secondaryKey, if(equals(reference('redisDatabase').clientProtocol, 'Plaintext'), 'False', 'True')))), 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.33.93.31351", + "templateHash": "8063348652715653257" + } + }, + "definitions": { + "secretSetOutputType": { + "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." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "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." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "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]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "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]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + }, + "dependsOn": [ + "redisCluster", + "redisDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Redis database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the database." + }, + "value": "[resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Redis resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "port": { + "type": "int", + "metadata": { + "description": "The Redis database port." + }, + "value": "[reference('redisDatabase').port]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The Redis endpoint." + }, + "value": "[format('{0}:{1}', reference('redisCluster').hostName, reference('redisDatabase').port)]" + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + } + } +} diff --git a/avm/res/cache/redis-enterprise/database/modules/keyVaultExport.bicep b/avm/res/cache/redis-enterprise/database/modules/keyVaultExport.bicep new file mode 100644 index 0000000000..173266421b --- /dev/null +++ b/avm/res/cache/redis-enterprise/database/modules/keyVaultExport.bicep @@ -0,0 +1,43 @@ +// ============== // +// Parameters // +// ============== // + +@description('Required. The name of the Key Vault to set the secrets in.') +param keyVaultName string + +import { secretToSetType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Required. The secrets to set in the Key Vault.') +param secretsToSet secretToSetType[] + +// ============= // +// Resources // +// ============= // + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = { + name: keyVaultName +} + +resource secrets 'Microsoft.KeyVault/vaults/secrets@2023-07-01' = [ + for secret in secretsToSet: { + name: secret.name + parent: keyVault + properties: { + value: secret.value + } + } +] + +// =========== // +// Outputs // +// =========== // + +import { secretSetOutputType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('The references to the secrets exported to the provided Key Vault.') +output secretsSet secretSetOutputType[] = [ + #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 + secretUriWithVersion: secrets[index].properties.secretUriWithVersion + } +] diff --git a/avm/res/cache/redis-enterprise/main.bicep b/avm/res/cache/redis-enterprise/main.bicep new file mode 100644 index 0000000000..be6a15d848 --- /dev/null +++ b/avm/res/cache/redis-enterprise/main.bicep @@ -0,0 +1,517 @@ +metadata name = 'Redis Enterprise and Azure Managed Redis (Preview)' +metadata description = 'This module deploys a Redis Enterprise or Azure Managed Redis (Preview) cache.' +metadata owner = 'Azure/module-maintainers' + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Required. The name of the cache resource.') +param name string + +import { lockType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The lock settings of the service.') +param lock lockType? + +import { roleAssignmentType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Array of role assignments to create.') +param roleAssignments roleAssignmentType[]? + +@description('Optional. Tags of the resource.') +param tags object? + +import { managedIdentityOnlyUserAssignedType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Conditional. The managed identity definition for this resource. Required if \'customerManagedKey\' is not empty.') +param managedIdentities managedIdentityOnlyUserAssignedType? + +import { customerManagedKeyType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The customer managed key definition to use for the managed service.') +param customerManagedKey customerManagedKeyType? + +@allowed([ + 'Enabled' + 'Disabled' +]) +@description('Optional. Specifies whether to enable data replication for high availability. Used only with Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. HIGH AVAILABILITY IS A PARAMETER USED FOR A PREVIEW FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-high-availability) FOR CLARIFICATION.') +param highAvailability string = 'Enabled' + +@allowed([ + '1.2' +]) +@description('Optional. The minimum TLS version for the Redis cluster to support.') +param minimumTlsVersion string = '1.2' + +@allowed([ + 2 + 3 + 4 + 6 + 8 + 9 + 10 +]) +@description('Optional. The size of the cluster. Only supported on Redis Enterprise SKUs: Enterprise, EnterpriseFlash. Valid values are (2, 4, 6, 8, 10) for Enterprise SKUs and (3, 9) for EnterpriseFlash SKUs. [Learn more](https://learn.microsoft.com/azure/azure-cache-for-redis/cache-best-practices-enterprise-tiers#sharding-and-cpu-utilization).') +param capacity int = 2 + +@allowed([ + 'Balanced_B0' + 'Balanced_B1' + 'Balanced_B3' + 'Balanced_B5' + 'Balanced_B10' + 'Balanced_B20' + 'Balanced_B50' + 'Balanced_B100' + 'Balanced_B150' + 'Balanced_B250' + 'Balanced_B350' + 'Balanced_B500' + 'Balanced_B700' + 'Balanced_B1000' + 'ComputeOptimized_X3' + 'ComputeOptimized_X5' + 'ComputeOptimized_X10' + 'ComputeOptimized_X20' + 'ComputeOptimized_X50' + 'ComputeOptimized_X100' + 'ComputeOptimized_X150' + 'ComputeOptimized_X250' + 'ComputeOptimized_X350' + 'ComputeOptimized_X500' + 'ComputeOptimized_X700' + 'Enterprise_E1' + 'Enterprise_E5' + 'Enterprise_E10' + 'Enterprise_E20' + 'Enterprise_E50' + 'Enterprise_E100' + 'Enterprise_E200' + 'Enterprise_E400' + 'EnterpriseFlash_F300' + 'EnterpriseFlash_F700' + 'EnterpriseFlash_F1500' + 'FlashOptimized_A250' + 'FlashOptimized_A500' + 'FlashOptimized_A700' + 'FlashOptimized_A1000' + 'FlashOptimized_A1500' + 'FlashOptimized_A2000' + 'FlashOptimized_A4500' + 'MemoryOptimized_M10' + 'MemoryOptimized_M20' + 'MemoryOptimized_M50' + 'MemoryOptimized_M100' + 'MemoryOptimized_M150' + 'MemoryOptimized_M250' + 'MemoryOptimized_M350' + 'MemoryOptimized_M500' + 'MemoryOptimized_M700' + 'MemoryOptimized_M1000' + 'MemoryOptimized_M1500' + 'MemoryOptimized_M2000' +]) +@description('Optional. The type of cluster to deploy. Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized ARE IN PREVIEW, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-overview#tiers-and-skus-at-a-glance) FOR CLARIFICATION.') +param skuName string = 'Enterprise_E5' + +@allowed([ + 1 + 2 + 3 +]) +@description('Optional. The Availability Zones to place the resources in. Currently only supported on Enterprise and EnterpriseFlash SKUs.') +param zones int[] = [ + 1 + 2 + 3 +] + +// ================ // +// Database params // +// ================ // +@description('Optional. Database configuration.') +param database databaseType? + +// ============ // +// Other params // +// ============ // + +import { privateEndpointSingleServiceType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible.') +param privateEndpoints privateEndpointSingleServiceType[]? + +import { diagnosticSettingMetricsOnlyType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('Optional. The cluster-level diagnostic settings of the service.') +param diagnosticSettings diagnosticSettingMetricsOnlyType[]? + +@description('Optional. Enable/Disable usage telemetry for module.') +param enableTelemetry bool = true + +var isAmr = startsWith(skuName, 'Balanced') || startsWith(skuName, 'ComputeOptimized') || startsWith( + skuName, + 'FlashOptimized' +) || startsWith(skuName, 'MemoryOptimized') +var isEnterprise = startsWith(skuName, 'Enterprise') || startsWith(skuName, 'EnterpriseFlash') + +var availabilityZones = isEnterprise ? map(zones, zone => string(zone)) : [] + +var formattedUserAssignedIdentities = reduce( + map((managedIdentities.?userAssignedResourceIds ?? []), (id) => { '${id}': {} }), + {}, + (cur, next) => union(cur, next) +) // Converts the flat array to an object like { '${id1}': {}, '${id2}': {} } + +var identity = !empty(managedIdentities) + ? { + type: !empty(managedIdentities.?userAssignedResourceIds ?? {}) ? 'UserAssigned' : 'None' + userAssignedIdentities: !empty(formattedUserAssignedIdentities) ? formattedUserAssignedIdentities : null + } + : null + +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') + 'Redis Cache Contributor': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'e0f68234-74aa-48ed-b826-c38b57376e17' + ) + 'Role Based Access Control Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'f58310d9-a9f6-439a-9e8d-f62e7b41a168' + ) + 'User Access Administrator': subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9' + ) +} + +var formattedRoleAssignments = [ + for (roleAssignment, index) in (roleAssignments ?? []): union(roleAssignment, { + roleDefinitionId: builtInRoleNames[?roleAssignment.roleDefinitionIdOrName] ?? (contains( + roleAssignment.roleDefinitionIdOrName, + '/providers/Microsoft.Authorization/roleDefinitions/' + ) + ? roleAssignment.roleDefinitionIdOrName + : subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleAssignment.roleDefinitionIdOrName)) + }) +] + +// ============== // +// Resources // +// ============== // + +#disable-next-line no-deployments-resources +resource avmTelemetry 'Microsoft.Resources/deployments@2024-03-01' = if (enableTelemetry) { + name: '46d3xbcp.res.cache-redisenterprise.${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 cMKKeyVault 'Microsoft.KeyVault/vaults@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId)) { + name: last(split(customerManagedKey.?keyVaultResourceId!, '/')) + scope: resourceGroup( + split(customerManagedKey.?keyVaultResourceId!, '/')[2], + split(customerManagedKey.?keyVaultResourceId!, '/')[4] + ) + + resource cMKKey 'keys@2023-02-01' existing = if (!empty(customerManagedKey.?keyVaultResourceId) && !empty(customerManagedKey.?keyName)) { + name: customerManagedKey.?keyName! + } +} + +resource cMKUserAssignedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-01-31' existing = if (!empty(customerManagedKey.?userAssignedIdentityResourceId)) { + name: last(split(customerManagedKey.?userAssignedIdentityResourceId!, '/')) + scope: resourceGroup( + split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[2], + split(customerManagedKey.?userAssignedIdentityResourceId!, '/')[4] + ) +} + +resource redisCluster 'Microsoft.Cache/redisEnterprise@2024-09-01-preview' = { + name: name + location: location + tags: tags + identity: identity + properties: { + encryption: !empty(customerManagedKey) + ? { + customerManagedKeyEncryption: { + keyEncryptionKeyIdentity: !empty(customerManagedKey.?userAssignedIdentityResourceId) + ? { + identityType: 'userAssignedIdentity' + userAssignedIdentityResourceId: cMKUserAssignedIdentity.id + } + : null + keyEncryptionKeyUrl: !empty(customerManagedKey.?keyVersion ?? '') + ? '${cMKKeyVault::cMKKey.properties.keyUri}/${customerManagedKey!.?keyVersion}' + : cMKKeyVault::cMKKey.properties.keyUriWithVersion + } + } + : null + highAvailability: isAmr ? highAvailability : null + minimumTlsVersion: minimumTlsVersion + } + sku: { + capacity: isEnterprise ? capacity : null + name: skuName + } + zones: !empty(availabilityZones) ? availabilityZones : null +} + +module redisCluster_database 'database/main.bicep' = { + name: '${uniqueString(deployment().name, location)}-redis-database' + params: { + name: database.?name + redisClusterName: redisCluster.name + accessKeysAuthentication: isAmr ? database.?accessKeysAuthentication : null + accessPolicyAssignments: isAmr ? database.?accessPolicyAssignments : null + clientProtocol: database.?clientProtocol + clusteringPolicy: database.?clusteringPolicy + deferUpgrade: database.?deferUpgrade + evictionPolicy: database.?evictionPolicy + geoReplication: database.?geoReplication + modules: database.?modules + port: database.?port + persistence: database.?persistence + secretsExportConfiguration: database.?secretsExportConfiguration + diagnosticSettings: database.?diagnosticSettings + } +} + +resource redisCluster_lock 'Microsoft.Authorization/locks@2020-05-01' = if (!empty(lock ?? {}) && lock.?kind != 'None') { + name: lock.?name ?? 'lock-${name}' + properties: { + level: lock.?kind ?? '' + notes: lock.?kind == 'CanNotDelete' + ? 'Cannot delete resource or child resources.' + : 'Cannot delete or modify the resource or child resources.' + } + scope: redisCluster +} + +resource redisCluster_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 + } + ] + marketplacePartnerId: diagnosticSetting.?marketplacePartnerResourceId + logAnalyticsDestinationType: diagnosticSetting.?logAnalyticsDestinationType + } + scope: redisCluster + } +] + +resource redisCluster_roleAssignments 'Microsoft.Authorization/roleAssignments@2022-04-01' = [ + for (roleAssignment, index) in (formattedRoleAssignments ?? []): { + name: roleAssignment.?name ?? guid(redisCluster.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: redisCluster + } +] + +module redisEnterprise_privateEndpoints 'br/public:avm/res/network/private-endpoint:0.10.1' = [ + for (privateEndpoint, index) in (privateEndpoints ?? []): { + name: '${uniqueString(deployment().name, location)}-redisEnterprise-PrivateEndpoint-${index}' + scope: resourceGroup( + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[2], + split(privateEndpoint.?resourceGroupResourceId ?? resourceGroup().id, '/')[4] + ) + params: { + name: privateEndpoint.?name ?? 'pep-${last(split(redisCluster.id, '/'))}-${privateEndpoint.?service ?? 'redisEnterprise'}-${index}' + privateLinkServiceConnections: privateEndpoint.?isManualConnection != true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(redisCluster.id, '/'))}-${privateEndpoint.?service ?? 'redisEnterprise'}-${index}' + properties: { + privateLinkServiceId: redisCluster.id + groupIds: [ + privateEndpoint.?service ?? 'redisEnterprise' + ] + } + } + ] + : null + manualPrivateLinkServiceConnections: privateEndpoint.?isManualConnection == true + ? [ + { + name: privateEndpoint.?privateLinkServiceConnectionName ?? '${last(split(redisCluster.id, '/'))}-${privateEndpoint.?service ?? 'redisEnterprise'}-${index}' + properties: { + privateLinkServiceId: redisCluster.id + groupIds: [ + privateEndpoint.?service ?? 'redisEnterprise' + ] + 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 + } + } +] + +// ============ // +// Outputs // +// ============ // + +@description('The name of the Redis cluster.') +output name string = redisCluster.name + +@description('The resource ID of the Redis cluster.') +output resourceId string = redisCluster.id + +@description('The name of the Redis database.') +output databaseName string = redisCluster_database.outputs.name + +@description('The resource ID of the database.') +output databaseResourceId string = redisCluster_database.outputs.resourceId + +@description('The name of the resource group the Redis resource was created in.') +output resourceGroupName string = resourceGroup().name + +@description('The Redis endpoint.') +output endpoint string = redisCluster_database.outputs.endpoint + +@description('The location the resource was deployed into.') +output location string = redisCluster.location + +@description('The private endpoints of the Redis resource.') +output privateEndpoints privateEndpointOutputType[] = [ + for (pe, index) in (privateEndpoints ?? []): { + name: redisEnterprise_privateEndpoints[index].outputs.name + resourceId: redisEnterprise_privateEndpoints[index].outputs.resourceId + groupId: redisEnterprise_privateEndpoints[index].outputs.?groupId! + customDnsConfigs: redisEnterprise_privateEndpoints[index].outputs.customDnsConfigs + networkInterfaceResourceIds: redisEnterprise_privateEndpoints[index].outputs.networkInterfaceResourceIds + } +] + +import { secretsOutputType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +@description('A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret\'s name.') +output exportedSecrets secretsOutputType = redisCluster_database.outputs.exportedSecrets + +// =============== // +// Definitions // +// =============== // + +import { diagnosticSettingLogsOnlyType } from 'br/public:avm/utl/types/avm-common-types:0.5.1' +import { geoReplicationType, moduleType, persistenceType, accessPolicyAssignmentType, secretsExportConfigurationType } from 'database/main.bicep' + +@export() +type databaseType = { + @description('Optional. Name of the database.') + name: ('default')? + + @description('Optional. Allow authentication via access keys. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication#disable-access-key-authentication-on-your-cache) FOR CLARIFICATION.') + accessKeysAuthentication: ('Disabled' | 'Enabled')? + + @description('Optional. Specifies whether Redis clients can connect using TLS-encrypted or plaintext Redis protocols.') + clientProtocol: ('Encrypted' | 'Plaintext')? + + @description('Optional. Redis clustering policy. [Learn more](https://aka.ms/redis/enterprise/clustering).') + clusteringPolicy: ('EnterpriseCluster' | 'OSSCluster')? + + @description('Optional. Specifies whether to defer future Redis major version upgrades by up to 90 days. [Learn more](https://aka.ms/redisversionupgrade#defer-upgrades).') + deferUpgrade: ('Deferred' | 'NotDeferred')? + + @description('Optional. Specifies the eviction policy for the Redis resource.') + evictionPolicy: ( + | 'AllKeysLFU' + | 'AllKeysLRU' + | 'AllKeysRandom' + | 'NoEviction' + | 'VolatileLFU' + | 'VolatileLRU' + | 'VolatileRandom' + | 'VolatileTTL')? + + @description('Optional. The active geo-replication settings of the service. All caches within a geo-replication group must have the same configuration.') + geoReplication: geoReplicationType? + + @description('Optional. Redis modules to enable. Restrictions may apply based on SKU and configuration. [Learn more](https://aka.ms/redis/enterprise/modules).') + modules: moduleType[]? + + @description('Optional. TCP port of the database endpoint.') + @minValue(10000) + @maxValue(10000) + port: int? + + @description('Optional. The persistence settings of the service.') + persistence: persistenceType? + + @description('Optional. Access policy assignments for Microsoft Entra authentication. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication) FOR CLARIFICATION.') + accessPolicyAssignments: accessPolicyAssignmentType[]? + + @description('Optional. Key vault reference and secret settings for the module\'s secrets export.') + secretsExportConfiguration: secretsExportConfigurationType? + + @description('Optional. The database-level diagnostic settings of the service.') + diagnosticSettings: diagnosticSettingLogsOnlyType[]? +} + +@export() +type privateEndpointOutputType = { + @description('The name of the private endpoint.') + name: string + + @description('The resource ID of the private endpoint.') + resourceId: string + + @description('The group Id for the private endpoint Group.') + groupId: string? + + @description('The custom DNS configurations of the private endpoint.') + customDnsConfigs: { + @description('FQDN that resolves to private endpoint IP address.') + fqdn: string? + + @description('A list of private IP addresses of the private endpoint.') + ipAddresses: string[] + }[] + + @description('The IDs of the network interfaces associated with the private endpoint.') + networkInterfaceResourceIds: string[] +} diff --git a/avm/res/cache/redis-enterprise/main.json b/avm/res/cache/redis-enterprise/main.json new file mode 100644 index 0000000000..56ee4d066e --- /dev/null +++ b/avm/res/cache/redis-enterprise/main.json @@ -0,0 +1,3312 @@ +{ + "$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.33.93.31351", + "templateHash": "11157703241699996924" + }, + "name": "Redis Enterprise and Azure Managed Redis (Preview)", + "description": "This module deploys a Redis Enterprise or Azure Managed Redis (Preview) cache.", + "owner": "Azure/module-maintainers" + }, + "definitions": { + "databaseType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "default" + ], + "nullable": true, + "metadata": { + "description": "Optional. Name of the database." + } + }, + "accessKeysAuthentication": { + "type": "string", + "allowedValues": [ + "Disabled", + "Enabled" + ], + "nullable": true, + "metadata": { + "description": "Optional. Allow authentication via access keys. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication#disable-access-key-authentication-on-your-cache) FOR CLARIFICATION." + } + }, + "clientProtocol": { + "type": "string", + "allowedValues": [ + "Encrypted", + "Plaintext" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether Redis clients can connect using TLS-encrypted or plaintext Redis protocols." + } + }, + "clusteringPolicy": { + "type": "string", + "allowedValues": [ + "EnterpriseCluster", + "OSSCluster" + ], + "nullable": true, + "metadata": { + "description": "Optional. Redis clustering policy. [Learn more](https://aka.ms/redis/enterprise/clustering)." + } + }, + "deferUpgrade": { + "type": "string", + "allowedValues": [ + "Deferred", + "NotDeferred" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies whether to defer future Redis major version upgrades by up to 90 days. [Learn more](https://aka.ms/redisversionupgrade#defer-upgrades)." + } + }, + "evictionPolicy": { + "type": "string", + "allowedValues": [ + "AllKeysLFU", + "AllKeysLRU", + "AllKeysRandom", + "NoEviction", + "VolatileLFU", + "VolatileLRU", + "VolatileRandom", + "VolatileTTL" + ], + "nullable": true, + "metadata": { + "description": "Optional. Specifies the eviction policy for the Redis resource." + } + }, + "geoReplication": { + "$ref": "#/definitions/geoReplicationType", + "nullable": true, + "metadata": { + "description": "Optional. The active geo-replication settings of the service. All caches within a geo-replication group must have the same configuration." + } + }, + "modules": { + "type": "array", + "items": { + "$ref": "#/definitions/moduleType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Redis modules to enable. Restrictions may apply based on SKU and configuration. [Learn more](https://aka.ms/redis/enterprise/modules)." + } + }, + "port": { + "type": "int", + "nullable": true, + "minValue": 10000, + "maxValue": 10000, + "metadata": { + "description": "Optional. TCP port of the database endpoint." + } + }, + "persistence": { + "$ref": "#/definitions/persistenceType", + "nullable": true, + "metadata": { + "description": "Optional. The persistence settings of the service." + } + }, + "accessPolicyAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/accessPolicyAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Access policy assignments for Microsoft Entra authentication. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication) FOR CLARIFICATION." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The database-level diagnostic settings of the service." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateEndpointOutputType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the private endpoint." + } + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the private endpoint." + } + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + } + }, + "customDnsConfigs": { + "type": "array", + "items": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "FQDN that resolves to private endpoint IP address." + } + }, + "ipAddresses": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "A list of private IP addresses of the private endpoint." + } + } + } + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + } + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The IDs of the network interfaces associated with the private endpoint." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "_1.privateEndpointCustomDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. 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." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointIpConfigurationType": { + "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." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.privateEndpointPrivateDnsZoneGroupType": { + "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." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_1.secretSetOutputType": { + "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." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "_2.aofPersistenceType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "aof" + ], + "metadata": { + "description": "Required. AOF persistence type." + } + }, + "frequency": { + "type": "string", + "allowedValues": [ + "1s" + ], + "metadata": { + "description": "Required. The frequency at which data is written to disk." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "database/main.bicep" + } + } + }, + "_2.disabledPersistenceType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "disabled" + ], + "metadata": { + "description": "Required. Disabled persistence type." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "database/main.bicep" + } + } + }, + "_2.linkedDatabaseType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of linked database. Should be in the form: `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cache/redisEnterprise/{redisName}/databases/default`." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "database/main.bicep" + } + } + }, + "_2.rdbPersistenceType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "rdb" + ], + "metadata": { + "description": "Required. RDB persistence type." + } + }, + "frequency": { + "type": "string", + "allowedValues": [ + "12h", + "1h", + "6h" + ], + "metadata": { + "description": "Required. The frequency at which an RDB snapshot of the database is created." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "database/main.bicep" + } + } + }, + "accessPolicyAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the access policy assignment." + } + }, + "userObjectId": { + "type": "string", + "metadata": { + "description": "Required. Object ID to which the access policy will be assigned." + } + }, + "accessPolicyName": { + "type": "string", + "allowedValues": [ + "default" + ], + "nullable": true, + "metadata": { + "description": "Optional. Name of the access policy to be assigned. The current only allowed name is 'default'." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "database/main.bicep" + } + } + }, + "customerManagedKeyType": { + "type": "object", + "properties": { + "keyVaultResourceId": { + "type": "string", + "metadata": { + "description": "Required. The resource ID of a key vault to reference a customer managed key for encryption from." + } + }, + "keyName": { + "type": "string", + "metadata": { + "description": "Required. The name of the customer managed key to use for encryption." + } + }, + "keyVersion": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The version of the customer managed key to reference for encryption. If not provided, the deployment will use the latest version available at deployment time." + } + }, + "userAssignedIdentityResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. User assigned identity to use when fetching the customer managed key. Required if no system assigned identity is available for use." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a customer-managed key. To be used if the resource type does not support auto-rotation of the customer-managed key.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingMetricsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "metricCategories": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "metadata": { + "description": "Required. Name of a Diagnostic Metric category for a resource type this setting is applied to. Set to `AllMetrics` to collect all metrics." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of 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." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only metrics are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "geoReplicationType": { + "type": "object", + "properties": { + "groupNickname": { + "type": "string", + "metadata": { + "description": "Required. The name of the geo-replication group." + } + }, + "linkedDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/_2.linkedDatabaseType" + }, + "metadata": { + "description": "Required. List of database resources to link with this database, including itself." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "database/main.bicep" + } + } + }, + "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." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "managedIdentityOnlyUserAssignedType": { + "type": "object", + "properties": { + "userAssignedResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "nullable": true, + "metadata": { + "description": "Optional. The resource ID(s) to assign to the resource. Required if a user assigned identity is used for encryption." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a managed identity configuration. To be used if only user-assigned identities are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "moduleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "RediSearch", + "RedisBloom", + "RedisJSON", + "RedisTimeSeries" + ], + "metadata": { + "description": "Required. The name of the module." + } + }, + "args": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Additional module arguments." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "database/main.bicep" + } + } + }, + "persistenceType": { + "type": "object", + "discriminator": { + "propertyName": "type", + "mapping": { + "disabled": { + "$ref": "#/definitions/_2.disabledPersistenceType" + }, + "aof": { + "$ref": "#/definitions/_2.aofPersistenceType" + }, + "rdb": { + "$ref": "#/definitions/_2.rdbPersistenceType" + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "database/main.bicep" + } + } + }, + "privateEndpointSingleServiceType": { + "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\" for a Key Vault Private Endpoint." + } + }, + "subnetResourceId": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of the subnet where the endpoint needs to be created." + } + }, + "resourceGroupResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The resource ID of the Resource Group the Private Endpoint will be created in. If not specified, the Resource Group of the provided Virtual Network Subnet is used." + } + }, + "privateDnsZoneGroup": { + "$ref": "#/definitions/_1.privateEndpointPrivateDnsZoneGroupType", + "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": { + "$ref": "#/definitions/_1.privateEndpointCustomDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/_1.privateEndpointIpConfigurationType" + }, + "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", + "nullable": true, + "metadata": { + "description": "Optional. Specify the type of lock." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "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." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a private endpoint. To be used if the private endpoint's default service / groupId can be assumed (i.e., for services that only have one Private Endpoint type like 'vault' for key vault).", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "roleAssignmentType": { + "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." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "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." + } + }, + "primaryAccessKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryAccessKey secret name to create." + } + }, + "primaryConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryConnectionString secret name to create." + } + }, + "primaryStackExchangeRedisConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryStackExchangeRedisConnectionString secret name to create." + } + }, + "secondaryAccessKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryAccessKey secret name to create." + } + }, + "secondaryConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryConnectionString secret name to create." + } + }, + "secondaryStackExchangeRedisConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryStackExchangeRedisConnectionString secret name to create." + } + } + }, + "metadata": { + "__bicep_imported_from!": { + "sourceTemplate": "database/main.bicep" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "location": { + "type": "string", + "defaultValue": "[resourceGroup().location]", + "metadata": { + "description": "Optional. Location for all resources." + } + }, + "name": { + "type": "string", + "metadata": { + "description": "Required. The name of the cache resource." + } + }, + "lock": { + "$ref": "#/definitions/lockType", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Array of role assignments to create." + } + }, + "tags": { + "type": "object", + "nullable": true, + "metadata": { + "description": "Optional. Tags of the resource." + } + }, + "managedIdentities": { + "$ref": "#/definitions/managedIdentityOnlyUserAssignedType", + "nullable": true, + "metadata": { + "description": "Conditional. The managed identity definition for this resource. Required if 'customerManagedKey' is not empty." + } + }, + "customerManagedKey": { + "$ref": "#/definitions/customerManagedKeyType", + "nullable": true, + "metadata": { + "description": "Optional. The customer managed key definition to use for the managed service." + } + }, + "highAvailability": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Specifies whether to enable data replication for high availability. Used only with Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. HIGH AVAILABILITY IS A PARAMETER USED FOR A PREVIEW FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-high-availability) FOR CLARIFICATION." + } + }, + "minimumTlsVersion": { + "type": "string", + "defaultValue": "1.2", + "allowedValues": [ + "1.2" + ], + "metadata": { + "description": "Optional. The minimum TLS version for the Redis cluster to support." + } + }, + "capacity": { + "type": "int", + "defaultValue": 2, + "allowedValues": [ + 2, + 3, + 4, + 6, + 8, + 9, + 10 + ], + "metadata": { + "description": "Optional. The size of the cluster. Only supported on Redis Enterprise SKUs: Enterprise, EnterpriseFlash. Valid values are (2, 4, 6, 8, 10) for Enterprise SKUs and (3, 9) for EnterpriseFlash SKUs. [Learn more](https://learn.microsoft.com/azure/azure-cache-for-redis/cache-best-practices-enterprise-tiers#sharding-and-cpu-utilization)." + } + }, + "skuName": { + "type": "string", + "defaultValue": "Enterprise_E5", + "allowedValues": [ + "Balanced_B0", + "Balanced_B1", + "Balanced_B3", + "Balanced_B5", + "Balanced_B10", + "Balanced_B20", + "Balanced_B50", + "Balanced_B100", + "Balanced_B150", + "Balanced_B250", + "Balanced_B350", + "Balanced_B500", + "Balanced_B700", + "Balanced_B1000", + "ComputeOptimized_X3", + "ComputeOptimized_X5", + "ComputeOptimized_X10", + "ComputeOptimized_X20", + "ComputeOptimized_X50", + "ComputeOptimized_X100", + "ComputeOptimized_X150", + "ComputeOptimized_X250", + "ComputeOptimized_X350", + "ComputeOptimized_X500", + "ComputeOptimized_X700", + "Enterprise_E1", + "Enterprise_E5", + "Enterprise_E10", + "Enterprise_E20", + "Enterprise_E50", + "Enterprise_E100", + "Enterprise_E200", + "Enterprise_E400", + "EnterpriseFlash_F300", + "EnterpriseFlash_F700", + "EnterpriseFlash_F1500", + "FlashOptimized_A250", + "FlashOptimized_A500", + "FlashOptimized_A700", + "FlashOptimized_A1000", + "FlashOptimized_A1500", + "FlashOptimized_A2000", + "FlashOptimized_A4500", + "MemoryOptimized_M10", + "MemoryOptimized_M20", + "MemoryOptimized_M50", + "MemoryOptimized_M100", + "MemoryOptimized_M150", + "MemoryOptimized_M250", + "MemoryOptimized_M350", + "MemoryOptimized_M500", + "MemoryOptimized_M700", + "MemoryOptimized_M1000", + "MemoryOptimized_M1500", + "MemoryOptimized_M2000" + ], + "metadata": { + "description": "Optional. The type of cluster to deploy. Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized ARE IN PREVIEW, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-overview#tiers-and-skus-at-a-glance) FOR CLARIFICATION." + } + }, + "zones": { + "type": "array", + "items": { + "type": "int" + }, + "defaultValue": [ + 1, + 2, + 3 + ], + "allowedValues": [ + 1, + 2, + 3 + ], + "metadata": { + "description": "Optional. The Availability Zones to place the resources in. Currently only supported on Enterprise and EnterpriseFlash SKUs." + } + }, + "database": { + "$ref": "#/definitions/databaseType", + "nullable": true, + "metadata": { + "description": "Optional. Database configuration." + } + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointSingleServiceType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Configuration details for private endpoints. For security reasons, it is recommended to use private endpoints whenever possible." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingMetricsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The cluster-level diagnostic settings of the service." + } + }, + "enableTelemetry": { + "type": "bool", + "defaultValue": true, + "metadata": { + "description": "Optional. Enable/Disable usage telemetry for module." + } + } + }, + "variables": { + "copy": [ + { + "name": "formattedRoleAssignments", + "count": "[length(coalesce(parameters('roleAssignments'), createArray()))]", + "input": "[union(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')], createObject('roleDefinitionId', coalesce(tryGet(variables('builtInRoleNames'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName), if(contains(coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, '/providers/Microsoft.Authorization/roleDefinitions/'), coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', coalesce(parameters('roleAssignments'), createArray())[copyIndex('formattedRoleAssignments')].roleDefinitionIdOrName)))))]" + } + ], + "isAmr": "[or(or(or(startsWith(parameters('skuName'), 'Balanced'), startsWith(parameters('skuName'), 'ComputeOptimized')), startsWith(parameters('skuName'), 'FlashOptimized')), startsWith(parameters('skuName'), 'MemoryOptimized'))]", + "isEnterprise": "[or(startsWith(parameters('skuName'), 'Enterprise'), startsWith(parameters('skuName'), 'EnterpriseFlash'))]", + "availabilityZones": "[if(variables('isEnterprise'), map(parameters('zones'), lambda('zone', string(lambdaVariables('zone')))), createArray())]", + "formattedUserAssignedIdentities": "[reduce(map(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createArray()), lambda('id', createObject(format('{0}', lambdaVariables('id')), createObject()))), createObject(), lambda('cur', 'next', union(lambdaVariables('cur'), lambdaVariables('next'))))]", + "identity": "[if(not(empty(parameters('managedIdentities'))), createObject('type', if(not(empty(coalesce(tryGet(parameters('managedIdentities'), 'userAssignedResourceIds'), createObject()))), 'UserAssigned', 'None'), 'userAssignedIdentities', if(not(empty(variables('formattedUserAssignedIdentities'))), variables('formattedUserAssignedIdentities'), null())), null())]", + "builtInRoleNames": { + "Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]", + "Owner": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]", + "Reader": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]", + "Redis Cache Contributor": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'e0f68234-74aa-48ed-b826-c38b57376e17')]", + "Role Based Access Control Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'f58310d9-a9f6-439a-9e8d-f62e7b41a168')]", + "User Access Administrator": "[subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9')]" + } + }, + "resources": { + "cMKKeyVault::cMKKey": { + "condition": "[and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), and(not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'))), not(empty(tryGet(parameters('customerManagedKey'), 'keyName')))))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults/keys", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[format('{0}/{1}', last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')), tryGet(parameters('customerManagedKey'), 'keyName'))]" + }, + "avmTelemetry": { + "condition": "[parameters('enableTelemetry')]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2024-03-01", + "name": "[format('46d3xbcp.res.cache-redisenterprise.{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" + } + } + } + } + }, + "cMKKeyVault": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId')))]", + "existing": true, + "type": "Microsoft.KeyVault/vaults", + "apiVersion": "2023-02-01", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'keyVaultResourceId'), '/'))]" + }, + "cMKUserAssignedIdentity": { + "condition": "[not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId')))]", + "existing": true, + "type": "Microsoft.ManagedIdentity/userAssignedIdentities", + "apiVersion": "2023-01-31", + "subscriptionId": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]]", + "name": "[last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/'))]" + }, + "redisCluster": { + "type": "Microsoft.Cache/redisEnterprise", + "apiVersion": "2024-09-01-preview", + "name": "[parameters('name')]", + "location": "[parameters('location')]", + "tags": "[parameters('tags')]", + "identity": "[variables('identity')]", + "properties": { + "encryption": "[if(not(empty(parameters('customerManagedKey'))), createObject('customerManagedKeyEncryption', createObject('keyEncryptionKeyIdentity', if(not(empty(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'))), createObject('identityType', 'userAssignedIdentity', 'userAssignedIdentityResourceId', extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[2], split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')[4]), 'Microsoft.ManagedIdentity/userAssignedIdentities', last(split(tryGet(parameters('customerManagedKey'), 'userAssignedIdentityResourceId'), '/')))), null()), 'keyEncryptionKeyUrl', if(not(empty(coalesce(tryGet(parameters('customerManagedKey'), 'keyVersion'), ''))), format('{0}/{1}', reference('cMKKeyVault::cMKKey').keyUri, tryGet(parameters('customerManagedKey'), 'keyVersion')), reference('cMKKeyVault::cMKKey').keyUriWithVersion))), null())]", + "highAvailability": "[if(variables('isAmr'), parameters('highAvailability'), null())]", + "minimumTlsVersion": "[parameters('minimumTlsVersion')]" + }, + "sku": { + "capacity": "[if(variables('isEnterprise'), parameters('capacity'), null())]", + "name": "[parameters('skuName')]" + }, + "zones": "[if(not(empty(variables('availabilityZones'))), variables('availabilityZones'), null())]", + "dependsOn": [ + "cMKKeyVault::cMKKey" + ] + }, + "redisCluster_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.Cache/redisEnterprise/{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": [ + "redisCluster" + ] + }, + "redisCluster_diagnosticSettings": { + "copy": { + "name": "redisCluster_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Cache/redisEnterprise/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "metrics", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics'))))]", + "input": { + "category": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')].category]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'metricCategories'), createArray(createObject('category', 'AllMetrics')))[copyIndex('metrics')], 'enabled'), true())]", + "timeGrain": null + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "redisCluster" + ] + }, + "redisCluster_roleAssignments": { + "copy": { + "name": "redisCluster_roleAssignments", + "count": "[length(coalesce(variables('formattedRoleAssignments'), createArray()))]" + }, + "type": "Microsoft.Authorization/roleAssignments", + "apiVersion": "2022-04-01", + "scope": "[format('Microsoft.Cache/redisEnterprise/{0}', parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(variables('formattedRoleAssignments'), createArray())[copyIndex()], 'name'), guid(resourceId('Microsoft.Cache/redisEnterprise', 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": [ + "redisCluster" + ] + }, + "redisCluster_database": { + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-redis-database', uniqueString(deployment().name, parameters('location')))]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[tryGet(parameters('database'), 'name')]" + }, + "redisClusterName": { + "value": "[parameters('name')]" + }, + "accessKeysAuthentication": "[if(variables('isAmr'), createObject('value', tryGet(parameters('database'), 'accessKeysAuthentication')), createObject('value', null()))]", + "accessPolicyAssignments": "[if(variables('isAmr'), createObject('value', tryGet(parameters('database'), 'accessPolicyAssignments')), createObject('value', null()))]", + "clientProtocol": { + "value": "[tryGet(parameters('database'), 'clientProtocol')]" + }, + "clusteringPolicy": { + "value": "[tryGet(parameters('database'), 'clusteringPolicy')]" + }, + "deferUpgrade": { + "value": "[tryGet(parameters('database'), 'deferUpgrade')]" + }, + "evictionPolicy": { + "value": "[tryGet(parameters('database'), 'evictionPolicy')]" + }, + "geoReplication": { + "value": "[tryGet(parameters('database'), 'geoReplication')]" + }, + "modules": { + "value": "[tryGet(parameters('database'), 'modules')]" + }, + "port": { + "value": "[tryGet(parameters('database'), 'port')]" + }, + "persistence": { + "value": "[tryGet(parameters('database'), 'persistence')]" + }, + "secretsExportConfiguration": { + "value": "[tryGet(parameters('database'), 'secretsExportConfiguration')]" + }, + "diagnosticSettings": { + "value": "[tryGet(parameters('database'), 'diagnosticSettings')]" + } + }, + "template": { + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#", + "languageVersion": "2.0", + "contentVersion": "1.0.0.0", + "metadata": { + "_generator": { + "name": "bicep", + "version": "0.33.93.31351", + "templateHash": "12094637252334328193" + }, + "name": "Redis database", + "description": "This module deploys a Redis database in a Redis Enterprise or Azure Managed Redis (Preview) cluster." + }, + "definitions": { + "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." + } + }, + "primaryAccessKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryAccessKey secret name to create." + } + }, + "primaryConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryConnectionString secret name to create." + } + }, + "primaryStackExchangeRedisConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The primaryStackExchangeRedisConnectionString secret name to create." + } + }, + "secondaryAccessKeyName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryAccessKey secret name to create." + } + }, + "secondaryConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryConnectionString secret name to create." + } + }, + "secondaryStackExchangeRedisConnectionStringName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The secondaryStackExchangeRedisConnectionString secret name to create." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "disabledPersistenceType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "disabled" + ], + "metadata": { + "description": "Required. Disabled persistence type." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "aofPersistenceType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "aof" + ], + "metadata": { + "description": "Required. AOF persistence type." + } + }, + "frequency": { + "type": "string", + "allowedValues": [ + "1s" + ], + "metadata": { + "description": "Required. The frequency at which data is written to disk." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "rdbPersistenceType": { + "type": "object", + "properties": { + "type": { + "type": "string", + "allowedValues": [ + "rdb" + ], + "metadata": { + "description": "Required. RDB persistence type." + } + }, + "frequency": { + "type": "string", + "allowedValues": [ + "12h", + "1h", + "6h" + ], + "metadata": { + "description": "Required. The frequency at which an RDB snapshot of the database is created." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "persistenceType": { + "type": "object", + "discriminator": { + "propertyName": "type", + "mapping": { + "disabled": { + "$ref": "#/definitions/disabledPersistenceType" + }, + "aof": { + "$ref": "#/definitions/aofPersistenceType" + }, + "rdb": { + "$ref": "#/definitions/rdbPersistenceType" + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "moduleType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "allowedValues": [ + "RediSearch", + "RedisBloom", + "RedisJSON", + "RedisTimeSeries" + ], + "metadata": { + "description": "Required. The name of the module." + } + }, + "args": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Additional module arguments." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "geoReplicationType": { + "type": "object", + "properties": { + "groupNickname": { + "type": "string", + "metadata": { + "description": "Required. The name of the geo-replication group." + } + }, + "linkedDatabases": { + "type": "array", + "items": { + "$ref": "#/definitions/linkedDatabaseType" + }, + "metadata": { + "description": "Required. List of database resources to link with this database, including itself." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "linkedDatabaseType": { + "type": "object", + "properties": { + "id": { + "type": "string", + "metadata": { + "description": "Required. Resource ID of linked database. Should be in the form: `/subscriptions/{subscriptionId}/resourceGroups/{resourceGroupName}/providers/Microsoft.Cache/redisEnterprise/{redisName}/databases/default`." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "accessPolicyAssignmentType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the access policy assignment." + } + }, + "userObjectId": { + "type": "string", + "metadata": { + "description": "Required. Object ID to which the access policy will be assigned." + } + }, + "accessPolicyName": { + "type": "string", + "allowedValues": [ + "default" + ], + "nullable": true, + "metadata": { + "description": "Optional. Name of the access policy to be assigned. The current only allowed name is 'default'." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "_1.secretSetOutputType": { + "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." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "diagnosticSettingLogsOnlyType": { + "type": "object", + "properties": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The name of diagnostic setting." + } + }, + "logCategoriesAndGroups": { + "type": "array", + "items": { + "type": "object", + "properties": { + "category": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category for a resource type this setting is applied to. Set the specific logs to collect here." + } + }, + "categoryGroup": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of a Diagnostic Log category group for a resource type this setting is applied to. Set to `allLogs` to collect all logs." + } + }, + "enabled": { + "type": "bool", + "nullable": true, + "metadata": { + "description": "Optional. Enable or disable the category explicitly. Default is `true`." + } + } + } + }, + "nullable": true, + "metadata": { + "description": "Optional. The name of logs that will be streamed. \"allLogs\" includes all possible logs for the resource. Set to `[]` to disable log collection." + } + }, + "logAnalyticsDestinationType": { + "type": "string", + "allowedValues": [ + "AzureDiagnostics", + "Dedicated" + ], + "nullable": true, + "metadata": { + "description": "Optional. A string indicating whether the export to Log Analytics should use the default destination type, i.e. AzureDiagnostics, or use a destination type." + } + }, + "workspaceResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic log analytics workspace. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "storageAccountResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic storage account. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "eventHubAuthorizationRuleResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Resource ID of the diagnostic event hub authorization rule for the Event Hubs namespace in which the event hub should be created or streamed to." + } + }, + "eventHubName": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the diagnostic event hub within the namespace to which logs are streamed. Without this, an event hub is created for each log category. For security reasons, it is recommended to set diagnostic settings to send data to either storage account, log analytics workspace or event hub." + } + }, + "marketplacePartnerResourceId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. The full ARM resource ID of the Marketplace resource to which you would like to send Diagnostic Logs." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a diagnostic setting. To be used if only logs are supported by the resource provider.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "secretsOutputType": { + "type": "object", + "properties": {}, + "additionalProperties": { + "$ref": "#/definitions/_1.secretSetOutputType", + "metadata": { + "description": "An exported secret's references." + } + }, + "metadata": { + "description": "A map of the exported secrets", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "parameters": { + "redisClusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Redis Enterprise or Azure Managed Redis (Preview) resource. Required if the template is used in a standalone deployment." + } + }, + "name": { + "type": "string", + "defaultValue": "default", + "allowedValues": [ + "default" + ], + "metadata": { + "description": "Optional. Name of the database." + } + }, + "accessKeysAuthentication": { + "type": "string", + "defaultValue": "Enabled", + "allowedValues": [ + "Enabled", + "Disabled" + ], + "metadata": { + "description": "Optional. Allow authentication via access keys. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication#disable-access-key-authentication-on-your-cache) FOR CLARIFICATION." + } + }, + "clientProtocol": { + "type": "string", + "defaultValue": "Encrypted", + "allowedValues": [ + "Encrypted", + "Plaintext" + ], + "metadata": { + "description": "Optional. Specifies whether Redis clients can connect using TLS-encrypted or plaintext Redis protocols." + } + }, + "clusteringPolicy": { + "type": "string", + "defaultValue": "OSSCluster", + "allowedValues": [ + "EnterpriseCluster", + "OSSCluster" + ], + "metadata": { + "description": "Optional. Redis clustering policy. [Learn more](https://aka.ms/redis/enterprise/clustering)." + } + }, + "deferUpgrade": { + "type": "string", + "defaultValue": "NotDeferred", + "allowedValues": [ + "Deferred", + "NotDeferred" + ], + "metadata": { + "description": "Optional. Specifies whether to defer future Redis major version upgrades by up to 90 days. [Learn more](https://aka.ms/redisversionupgrade#defer-upgrades)." + } + }, + "evictionPolicy": { + "type": "string", + "defaultValue": "VolatileLRU", + "allowedValues": [ + "AllKeysLFU", + "AllKeysLRU", + "AllKeysRandom", + "NoEviction", + "VolatileLFU", + "VolatileLRU", + "VolatileRandom", + "VolatileTTL" + ], + "metadata": { + "description": "Optional. Specifies the eviction policy for the Redis resource." + } + }, + "geoReplication": { + "$ref": "#/definitions/geoReplicationType", + "nullable": true, + "metadata": { + "description": "Optional. The active geo-replication settings of the service. All caches within a geo-replication group must have the same configuration." + } + }, + "modules": { + "type": "array", + "items": { + "$ref": "#/definitions/moduleType" + }, + "defaultValue": [], + "metadata": { + "description": "Optional. Redis modules to enable. Restrictions may apply based on SKU and configuration. [Learn more](https://aka.ms/redis/enterprise/modules)." + } + }, + "port": { + "type": "int", + "defaultValue": 10000, + "minValue": 10000, + "maxValue": 10000, + "metadata": { + "description": "Optional. TCP port of the database endpoint." + } + }, + "persistence": { + "$ref": "#/definitions/persistenceType", + "defaultValue": { + "type": "disabled" + }, + "metadata": { + "description": "Optional. The persistence settings of the service." + } + }, + "accessPolicyAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/accessPolicyAssignmentType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Access policy assignments for Microsoft Entra authentication. Only supported on Azure Managed Redis (Preview) SKUs: Balanced, ComputeOptimized, FlashOptimized, and MemoryOptimized. THIS IS A PARAMETER USED FOR A PREVIEW SERVICE/FEATURE, MICROSOFT MAY NOT PROVIDE SUPPORT FOR THIS, PLEASE CHECK THE [PRODUCT DOCS](https://learn.microsoft.com/azure/azure-cache-for-redis/managed-redis/managed-redis-entra-for-authentication) FOR CLARIFICATION." + } + }, + "secretsExportConfiguration": { + "$ref": "#/definitions/secretsExportConfigurationType", + "nullable": true, + "metadata": { + "description": "Optional. Key vault reference and secret settings for the module's secrets export." + } + }, + "diagnosticSettings": { + "type": "array", + "items": { + "$ref": "#/definitions/diagnosticSettingLogsOnlyType" + }, + "nullable": true, + "metadata": { + "description": "Optional. The database-level diagnostic settings of the service." + } + } + }, + "resources": { + "redisCluster": { + "existing": true, + "type": "Microsoft.Cache/redisEnterprise", + "apiVersion": "2024-09-01-preview", + "name": "[parameters('redisClusterName')]" + }, + "redisDatabase": { + "type": "Microsoft.Cache/redisEnterprise/databases", + "apiVersion": "2024-09-01-preview", + "name": "[format('{0}/{1}', parameters('redisClusterName'), parameters('name'))]", + "properties": { + "accessKeysAuthentication": "[if(or(or(or(startsWith(reference('redisCluster', '2024-09-01-preview', 'full').sku.name, 'Balanced'), startsWith(reference('redisCluster', '2024-09-01-preview', 'full').sku.name, 'ComputeOptimized')), startsWith(reference('redisCluster', '2024-09-01-preview', 'full').sku.name, 'FlashOptimized')), startsWith(reference('redisCluster', '2024-09-01-preview', 'full').sku.name, 'MemoryOptimized')), parameters('accessKeysAuthentication'), null())]", + "clientProtocol": "[parameters('clientProtocol')]", + "clusteringPolicy": "[parameters('clusteringPolicy')]", + "deferUpgrade": "[parameters('deferUpgrade')]", + "evictionPolicy": "[parameters('evictionPolicy')]", + "geoReplication": "[if(not(empty(parameters('geoReplication'))), parameters('geoReplication'), null())]", + "modules": "[parameters('modules')]", + "port": "[parameters('port')]", + "persistence": "[if(not(equals(parameters('persistence').type, 'disabled')), createObject('aofEnabled', equals(parameters('persistence').type, 'aof'), 'rdbEnabled', equals(parameters('persistence').type, 'rdb'), 'aofFrequency', if(equals(parameters('persistence').type, 'aof'), parameters('persistence').frequency, null()), 'rdbFrequency', if(equals(parameters('persistence').type, 'rdb'), parameters('persistence').frequency, null())), null())]" + }, + "dependsOn": [ + "redisCluster" + ] + }, + "database_diagnosticSettings": { + "copy": { + "name": "database_diagnosticSettings", + "count": "[length(coalesce(parameters('diagnosticSettings'), createArray()))]" + }, + "type": "Microsoft.Insights/diagnosticSettings", + "apiVersion": "2021-05-01-preview", + "scope": "[format('Microsoft.Cache/redisEnterprise/{0}/databases/{1}', parameters('redisClusterName'), parameters('name'))]", + "name": "[coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'name'), format('{0}-diagnosticSettings', parameters('name')))]", + "properties": { + "copy": [ + { + "name": "logs", + "count": "[length(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs'))))]", + "input": { + "categoryGroup": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'categoryGroup')]", + "category": "[tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'category')]", + "enabled": "[coalesce(tryGet(coalesce(tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logCategoriesAndGroups'), createArray(createObject('categoryGroup', 'allLogs')))[copyIndex('logs')], 'enabled'), true())]" + } + } + ], + "storageAccountId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'storageAccountResourceId')]", + "workspaceId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'workspaceResourceId')]", + "eventHubAuthorizationRuleId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubAuthorizationRuleResourceId')]", + "eventHubName": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'eventHubName')]", + "marketplacePartnerId": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'marketplacePartnerResourceId')]", + "logAnalyticsDestinationType": "[tryGet(coalesce(parameters('diagnosticSettings'), createArray())[copyIndex()], 'logAnalyticsDestinationType')]" + }, + "dependsOn": [ + "redisDatabase" + ] + }, + "database_accessPolicyAssignments": { + "copy": { + "name": "database_accessPolicyAssignments", + "count": "[length(coalesce(parameters('accessPolicyAssignments'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-redis-apa-{1}', uniqueString(deployment().name), copyIndex())]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "name": { + "value": "[coalesce(parameters('accessPolicyAssignments'), createArray())[copyIndex()].name]" + }, + "clusterName": { + "value": "[parameters('redisClusterName')]" + }, + "databaseName": { + "value": "[parameters('name')]" + }, + "accessPolicyName": { + "value": "[tryGet(coalesce(parameters('accessPolicyAssignments'), createArray())[copyIndex()], 'accessPolicyName')]" + }, + "userObjectId": { + "value": "[coalesce(parameters('accessPolicyAssignments'), createArray())[copyIndex()].userObjectId]" + } + }, + "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.33.93.31351", + "templateHash": "6473026260124919331" + }, + "name": "Azure Managed Redis (Preview) Database Access Policy Assignment", + "description": "This module deploys an access policy assignment for an Azure Managed Redis (Preview) database." + }, + "parameters": { + "name": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. Name of the access policy assignment." + } + }, + "userObjectId": { + "type": "string", + "metadata": { + "description": "Required. Object ID to which the access policy will be assigned." + } + }, + "clusterName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the grandparent Azure Managed Redis (Preview) cluster. Required if the template is used in a standalone deployment." + } + }, + "databaseName": { + "type": "string", + "metadata": { + "description": "Conditional. The name of the parent Azure Managed Redis (Preview) database. Required if the template is used in a standalone deployment." + } + }, + "accessPolicyName": { + "type": "string", + "defaultValue": "default", + "allowedValues": [ + "default" + ], + "metadata": { + "description": "Optional. Name of the access policy to be assigned." + } + } + }, + "resources": { + "redisCluster::database": { + "existing": true, + "type": "Microsoft.Cache/redisEnterprise/databases", + "apiVersion": "2024-09-01-preview", + "name": "[format('{0}/{1}', parameters('clusterName'), parameters('databaseName'))]" + }, + "redisCluster": { + "existing": true, + "type": "Microsoft.Cache/redisEnterprise", + "apiVersion": "2024-09-01-preview", + "name": "[parameters('clusterName')]" + }, + "accessPolicyAssignment": { + "type": "Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments", + "apiVersion": "2024-09-01-preview", + "name": "[format('{0}/{1}/{2}', parameters('clusterName'), parameters('databaseName'), coalesce(parameters('name'), parameters('userObjectId')))]", + "properties": { + "accessPolicyName": "[parameters('accessPolicyName')]", + "user": { + "objectId": "[parameters('userObjectId')]" + } + } + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the access policy assignment." + }, + "value": "[coalesce(parameters('name'), parameters('userObjectId'))]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the access policy assignment." + }, + "value": "[resourceId('Microsoft.Cache/redisEnterprise/databases/accessPolicyAssignments', parameters('clusterName'), parameters('databaseName'), coalesce(parameters('name'), parameters('userObjectId')))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The resource group the access policy assignment was deployed into." + }, + "value": "[resourceGroup().name]" + }, + "userObjectId": { + "type": "string", + "metadata": { + "description": "The object ID of the user associated with the access policy." + }, + "value": "[reference('accessPolicyAssignment').user.objectId]" + } + } + } + }, + "dependsOn": [ + "redisDatabase" + ] + }, + "secretsExport": { + "condition": "[not(equals(parameters('secretsExportConfiguration'), null()))]", + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-secrets-kv', uniqueString(deployment().name))]", + "subscriptionId": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[2]]", + "resourceGroup": "[split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/')[4]]", + "properties": { + "expressionEvaluationOptions": { + "scope": "inner" + }, + "mode": "Incremental", + "parameters": { + "keyVaultName": { + "value": "[last(split(tryGet(parameters('secretsExportConfiguration'), 'keyVaultResourceId'), '/'))]" + }, + "secretsToSet": { + "value": "[union(createArray(), if(contains(parameters('secretsExportConfiguration'), 'primaryAccessKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryAccessKeyName'), 'value', listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').primaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'primaryConnectionStringName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryConnectionStringName'), 'value', format('{0}:{1}@{2}:{3}', if(equals(reference('redisDatabase').clientProtocol, 'Plaintext'), 'redis://', 'rediss://'), listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').primaryKey, reference('redisCluster').hostName, reference('redisDatabase').port))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'primaryStackExchangeRedisConnectionStringName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'primaryStackExchangeRedisConnectionStringName'), 'value', format('{0}:{1},password={2},ssl={3},abortConnect=False', reference('redisCluster').hostName, reference('redisDatabase').port, listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').primaryKey, if(equals(reference('redisDatabase').clientProtocol, 'Plaintext'), 'False', 'True')))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryAccessKeyName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryAccessKeyName'), 'value', listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').secondaryKey)), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryConnectionStringName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryConnectionStringName'), 'value', format('{0}:{1}@{2}:{3}', if(equals(reference('redisDatabase').clientProtocol, 'Plaintext'), 'redis://', 'rediss://'), listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').secondaryKey, reference('redisCluster').hostName, reference('redisDatabase').port))), createArray()), if(contains(parameters('secretsExportConfiguration'), 'secondaryStackExchangeRedisConnectionStringName'), createArray(createObject('name', tryGet(parameters('secretsExportConfiguration'), 'secondaryStackExchangeRedisConnectionStringName'), 'value', format('{0}:{1},password={2},ssl={3},abortConnect=False', reference('redisCluster').hostName, reference('redisDatabase').port, listKeys(resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name')), '2024-09-01-preview').secondaryKey, if(equals(reference('redisDatabase').clientProtocol, 'Plaintext'), 'False', 'True')))), 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.33.93.31351", + "templateHash": "8063348652715653257" + } + }, + "definitions": { + "secretSetOutputType": { + "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." + } + }, + "secretUriWithVersion": { + "type": "string", + "metadata": { + "description": "The secret URI with version of the exported secret." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the output of the secret set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "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." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for the secret to set via the secrets export feature.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "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]" + } + } + }, + "outputs": { + "secretsSet": { + "type": "array", + "items": { + "$ref": "#/definitions/secretSetOutputType" + }, + "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]", + "secretUriWithVersion": "[reference(format('secrets[{0}]', range(0, length(coalesce(parameters('secretsToSet'), createArray())))[copyIndex()])).secretUriWithVersion]" + } + } + } + } + } + }, + "dependsOn": [ + "redisCluster", + "redisDatabase" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Redis database." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the database." + }, + "value": "[resourceId('Microsoft.Cache/redisEnterprise/databases', parameters('redisClusterName'), parameters('name'))]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Redis resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "port": { + "type": "int", + "metadata": { + "description": "The Redis database port." + }, + "value": "[reference('redisDatabase').port]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The Redis endpoint." + }, + "value": "[format('{0}:{1}', reference('redisCluster').hostName, reference('redisDatabase').port)]" + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[if(not(equals(parameters('secretsExportConfiguration'), null())), toObject(reference('secretsExport').outputs.secretsSet.value, lambda('secret', last(split(lambdaVariables('secret').secretResourceId, '/'))), lambda('secret', lambdaVariables('secret'))), createObject())]" + } + } + } + }, + "dependsOn": [ + "redisCluster" + ] + }, + "redisEnterprise_privateEndpoints": { + "copy": { + "name": "redisEnterprise_privateEndpoints", + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]" + }, + "type": "Microsoft.Resources/deployments", + "apiVersion": "2022-09-01", + "name": "[format('{0}-redisEnterprise-PrivateEndpoint-{1}', uniqueString(deployment().name, parameters('location')), copyIndex())]", + "subscriptionId": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[2]]", + "resourceGroup": "[split(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'resourceGroupResourceId'), resourceGroup().id), '/')[4]]", + "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.Cache/redisEnterprise', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'redisEnterprise'), 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.Cache/redisEnterprise', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'redisEnterprise'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Cache/redisEnterprise', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'redisEnterprise')))))), 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.Cache/redisEnterprise', parameters('name')), '/')), coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'redisEnterprise'), copyIndex())), 'properties', createObject('privateLinkServiceId', resourceId('Microsoft.Cache/redisEnterprise', parameters('name')), 'groupIds', createArray(coalesce(tryGet(coalesce(parameters('privateEndpoints'), createArray())[copyIndex()], 'service'), 'redisEnterprise')), '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.33.13.18514", + "templateHash": "15954548978129725136" + }, + "name": "Private Endpoints", + "description": "This module deploys a Private Endpoint." + }, + "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." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "ipConfigurationType": { + "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." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "privateLinkServiceConnectionType": { + "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." + } + } + }, + "metadata": { + "__bicep_export!": true + } + }, + "customDnsConfigType": { + "type": "object", + "properties": { + "fqdn": { + "type": "string", + "nullable": true, + "metadata": { + "description": "Optional. 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." + } + } + }, + "metadata": { + "__bicep_export!": 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." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a lock.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + }, + "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" + } + } + }, + "roleAssignmentType": { + "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." + } + } + }, + "metadata": { + "description": "An AVM-aligned type for a role assignment.", + "__bicep_imported_from!": { + "sourceTemplate": "br:mcr.microsoft.com/bicep/avm/utl/types/avm-common-types:0.5.1" + } + } + } + }, + "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", + "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." + } + }, + "ipConfigurations": { + "type": "array", + "items": { + "$ref": "#/definitions/ipConfigurationType" + }, + "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." + } + }, + "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", + "nullable": true, + "metadata": { + "description": "Optional. The lock settings of the service." + } + }, + "roleAssignments": { + "type": "array", + "items": { + "$ref": "#/definitions/roleAssignmentType" + }, + "nullable": true, + "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": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "nullable": true, + "metadata": { + "description": "Optional. Custom DNS configurations." + } + }, + "manualPrivateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. 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. Required if `privateLinkServiceConnections` is empty." + } + }, + "privateLinkServiceConnections": { + "type": "array", + "items": { + "$ref": "#/definitions/privateLinkServiceConnectionType" + }, + "nullable": true, + "metadata": { + "description": "Conditional. A grouping of information about the connection to the remote resource. Required if `manualPrivateLinkServiceConnections` is empty." + } + }, + "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": "[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.10.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.33.13.18514", + "templateHash": "5440815542537978381" + }, + "name": "Private Endpoint Private DNS Zone Groups", + "description": "This module deploys a Private Endpoint Private DNS Zone Group." + }, + "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')]" + } + } + }, + "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]" + }, + "customDnsConfigs": { + "type": "array", + "items": { + "$ref": "#/definitions/customDnsConfigType" + }, + "metadata": { + "description": "The custom DNS configurations of the private endpoint." + }, + "value": "[reference('privateEndpoint').customDnsConfigs]" + }, + "networkInterfaceResourceIds": { + "type": "array", + "items": { + "type": "string" + }, + "metadata": { + "description": "The resource IDs of the network interfaces associated with the private endpoint." + }, + "value": "[map(reference('privateEndpoint').networkInterfaces, lambda('nic', lambdaVariables('nic').id))]" + }, + "groupId": { + "type": "string", + "nullable": true, + "metadata": { + "description": "The group Id for the private endpoint Group." + }, + "value": "[coalesce(tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'manualPrivateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0), tryGet(tryGet(tryGet(tryGet(reference('privateEndpoint'), 'privateLinkServiceConnections'), 0, 'properties'), 'groupIds'), 0))]" + } + } + } + }, + "dependsOn": [ + "redisCluster" + ] + } + }, + "outputs": { + "name": { + "type": "string", + "metadata": { + "description": "The name of the Redis cluster." + }, + "value": "[parameters('name')]" + }, + "resourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the Redis cluster." + }, + "value": "[resourceId('Microsoft.Cache/redisEnterprise', parameters('name'))]" + }, + "databaseName": { + "type": "string", + "metadata": { + "description": "The name of the Redis database." + }, + "value": "[reference('redisCluster_database').outputs.name.value]" + }, + "databaseResourceId": { + "type": "string", + "metadata": { + "description": "The resource ID of the database." + }, + "value": "[reference('redisCluster_database').outputs.resourceId.value]" + }, + "resourceGroupName": { + "type": "string", + "metadata": { + "description": "The name of the resource group the Redis resource was created in." + }, + "value": "[resourceGroup().name]" + }, + "endpoint": { + "type": "string", + "metadata": { + "description": "The Redis endpoint." + }, + "value": "[reference('redisCluster_database').outputs.endpoint.value]" + }, + "location": { + "type": "string", + "metadata": { + "description": "The location the resource was deployed into." + }, + "value": "[reference('redisCluster', '2024-09-01-preview', 'full').location]" + }, + "privateEndpoints": { + "type": "array", + "items": { + "$ref": "#/definitions/privateEndpointOutputType" + }, + "metadata": { + "description": "The private endpoints of the Redis resource." + }, + "copy": { + "count": "[length(coalesce(parameters('privateEndpoints'), createArray()))]", + "input": { + "name": "[reference(format('redisEnterprise_privateEndpoints[{0}]', copyIndex())).outputs.name.value]", + "resourceId": "[reference(format('redisEnterprise_privateEndpoints[{0}]', copyIndex())).outputs.resourceId.value]", + "groupId": "[tryGet(tryGet(reference(format('redisEnterprise_privateEndpoints[{0}]', copyIndex())).outputs, 'groupId'), 'value')]", + "customDnsConfigs": "[reference(format('redisEnterprise_privateEndpoints[{0}]', copyIndex())).outputs.customDnsConfigs.value]", + "networkInterfaceResourceIds": "[reference(format('redisEnterprise_privateEndpoints[{0}]', copyIndex())).outputs.networkInterfaceResourceIds.value]" + } + } + }, + "exportedSecrets": { + "$ref": "#/definitions/secretsOutputType", + "metadata": { + "description": "A hashtable of references to the secrets exported to the provided Key Vault. The key of each reference is each secret's name." + }, + "value": "[reference('redisCluster_database').outputs.exportedSecrets.value]" + } + } +} diff --git a/avm/res/cache/redis-enterprise/tests/e2e/active-geo-replication/dependencies.bicep b/avm/res/cache/redis-enterprise/tests/e2e/active-geo-replication/dependencies.bicep new file mode 100644 index 0000000000..b759cd2526 --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/active-geo-replication/dependencies.bicep @@ -0,0 +1,42 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Redis Enterprise cluster.') +param redisClusterName string + +@description('Optional. The name of the geo-replication group.') +param geoReplicationGroupName string = 'geo-replication-group' + +resource redisCluster 'Microsoft.Cache/redisEnterprise@2024-09-01-preview' = { + name: redisClusterName + location: location + sku: { + name: 'Balanced_B10' + } + + resource redisDatabase 'databases@2024-09-01-preview' = { + name: 'default' + properties: { + geoReplication: { + groupNickname: geoReplicationGroupName + linkedDatabases: [ + { + id: '${redisCluster.id}/databases/default' + } + ] + } + } + } +} + +@description('The resource ID of the created Redis database') +output redisDbResourceId string = redisCluster::redisDatabase.id + +@description('The location of the created Redis Cache') +output redisLocation string = redisCluster.location + +@description('The name of the created Redis Cache') +output redisClusterName string = redisCluster.name + +@description('The name of the geo-replication group') +output geoReplicationGroupName string = redisCluster::redisDatabase.properties.geoReplication.groupNickname diff --git a/avm/res/cache/redis-enterprise/tests/e2e/active-geo-replication/main.test.bicep b/avm/res/cache/redis-enterprise/tests/e2e/active-geo-replication/main.test.bicep new file mode 100644 index 0000000000..6ad2cbba2e --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/active-geo-replication/main.test.bicep @@ -0,0 +1,74 @@ +targetScope = 'subscription' + +metadata name = 'Active geo-replication' +metadata description = 'This instance deploys the module with active geo-replication enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-cache-redisenterprise-${serviceShort}-rg' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'creagr' + +@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_#' + +// Not all regions support zone-redundancy, so hardcoding 2 zone-enabled locations here +#disable-next-line no-hardcoded-location +var enforcedLocation = 'germanywestcentral' +#disable-next-line no-hardcoded-location +var enforcedPairedLocation = 'uksouth' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + redisClusterName: '${namePrefix}${serviceShort}001' + location: enforcedLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedPairedLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}002' + location: enforcedPairedLocation + skuName: 'Balanced_B10' + database: { + geoReplication: { + groupNickname: nestedDependencies.outputs.geoReplicationGroupName + linkedDatabases: [ + { + id: nestedDependencies.outputs.redisDbResourceId + } + { + id: '${resourceGroup.id}/providers/Microsoft.Cache/redisEnterprise/${namePrefix}${serviceShort}002/databases/default' + } + ] + } + } + } + } +] diff --git a/avm/res/cache/redis-enterprise/tests/e2e/amr-entra-id/dependencies.bicep b/avm/res/cache/redis-enterprise/tests/e2e/amr-entra-id/dependencies.bicep new file mode 100644 index 0000000000..d73a514a3c --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/amr-entra-id/dependencies.bicep @@ -0,0 +1,13 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to be created.') +param managedIdentityName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2023-07-31-preview' = { + name: managedIdentityName + location: location +} + +@description('The principal ID of the created Managed Identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId diff --git a/avm/res/cache/redis-enterprise/tests/e2e/amr-entra-id/main.test.bicep b/avm/res/cache/redis-enterprise/tests/e2e/amr-entra-id/main.test.bicep new file mode 100644 index 0000000000..905af1f642 --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/amr-entra-id/main.test.bicep @@ -0,0 +1,68 @@ +targetScope = 'subscription' + +metadata name = 'Azure Managed Redis (Preview) with Entra ID authentication' +metadata description = 'This instance deploys an Azure Managed Redis (Preview) cache with Entra ID authentication.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-cache-redisenterprise-${serviceShort}-rg' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'creaei' + +@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_#' + +// Hardcoded to 'uksouth' because AMR SKUs are not available in all regions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-nestedDependencies' + params: { + location: enforcedLocation + managedIdentityName: 'dep-${namePrefix}-mi-${serviceShort}' + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: enforcedLocation + skuName: 'Balanced_B10' + database: { + accessKeysAuthentication: 'Disabled' + accessPolicyAssignments: [ + { + name: 'assign1' + userObjectId: nestedDependencies.outputs.managedIdentityPrincipalId + } + ] + } + } + } +] diff --git a/avm/res/cache/redis-enterprise/tests/e2e/amr/main.test.bicep b/avm/res/cache/redis-enterprise/tests/e2e/amr/main.test.bicep new file mode 100644 index 0000000000..83b4090b45 --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/amr/main.test.bicep @@ -0,0 +1,49 @@ +targetScope = 'subscription' + +metadata name = 'Azure Managed Redis (Preview)' +metadata description = 'This instance deploys an Azure Managed Redis (Preview) cache 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}-cache-redisenterprise-${serviceShort}-rg' + +@description('Optional. A short identifier for the kind of deployment. Should be kept short to not run into resource-name length-constraints.') +param serviceShort string = 'creamr' + +@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_#' + +// Hardcoded to 'uksouth' because AMR SKUs are not available in all regions +#disable-next-line no-hardcoded-location +var enforcedLocation = 'uksouth' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: enforcedLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, enforcedLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + skuName: 'Balanced_B10' + } + } +] diff --git a/avm/res/cache/redis-enterprise/tests/e2e/defaults/main.test.bicep b/avm/res/cache/redis-enterprise/tests/e2e/defaults/main.test.bicep new file mode 100644 index 0000000000..a69a39227a --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/defaults/main.test.bicep @@ -0,0 +1,48 @@ +targetScope = 'subscription' + +metadata name = 'Using only defaults' +metadata description = 'This instance deploys the module with the minimum set of required parameters.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-cache-redisenterprise-${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 = 'cremin' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + skuName: 'Balanced_B10' + } + } +] diff --git a/avm/res/cache/redis-enterprise/tests/e2e/kv-secrets/dependencies.bicep b/avm/res/cache/redis-enterprise/tests/e2e/kv-secrets/dependencies.bicep new file mode 100644 index 0000000000..b93119b7bb --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/kv-secrets/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 created Key Vault.') +output keyVaultResourceId string = keyVault.id diff --git a/avm/res/cache/redis-enterprise/tests/e2e/kv-secrets/main.test.bicep b/avm/res/cache/redis-enterprise/tests/e2e/kv-secrets/main.test.bicep new file mode 100644 index 0000000000..553e9485eb --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/kv-secrets/main.test.bicep @@ -0,0 +1,62 @@ +targetScope = 'subscription' + +metadata name = 'Deploying with a key vault reference to save secrets' +metadata description = 'This instance deploys the module saving all 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}-cache-redisenterprise-${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 = 'crekvs' + +@description('Optional. A token to inject into the name of each resource.') +param namePrefix string = '#_namePrefix_#' + +// ============== // +// General resources +// ============== // +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +module testDeployment '../../../main.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}' + params: { + name: '${namePrefix}kvref' + skuName: 'Balanced_B10' + database: { + secretsExportConfiguration: { + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + primaryAccessKeyName: 'custom-primaryAccessKey-name' + primaryConnectionStringName: 'custom-primaryConnectionString-name' + primaryStackExchangeRedisConnectionStringName: 'custom-primaryStackExchangeRedisConnectionString-name' + secondaryAccessKeyName: 'custom-secondaryAccessKey-name' + secondaryConnectionStringName: 'custom-secondaryConnectionString-name' + secondaryStackExchangeRedisConnectionStringName: 'custom-secondaryStackExchangeRedisConnectionString-name' + } + } + } +} diff --git a/avm/res/cache/redis-enterprise/tests/e2e/max/dependencies.bicep b/avm/res/cache/redis-enterprise/tests/e2e/max/dependencies.bicep new file mode 100644 index 0000000000..c1b5396310 --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/max/dependencies.bicep @@ -0,0 +1,63 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the managed identity to create.') +param managedIdentityName string + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +var addressPrefix = '10.0.0.0/16' + +resource 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.redis.azure.net' + 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 +} + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The principal ID of the created managed identity.') +output managedIdentityPrincipalId string = managedIdentity.properties.principalId + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/res/cache/redis-enterprise/tests/e2e/max/main.test.bicep b/avm/res/cache/redis-enterprise/tests/e2e/max/main.test.bicep new file mode 100644 index 0000000000..6da9399595 --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/max/main.test.bicep @@ -0,0 +1,175 @@ +targetScope = 'subscription' + +metadata name = 'Using large parameter set' +metadata description = 'This instance deploys the module with most of its features enabled.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-cache-redisenterprise-${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 = 'cremax' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + managedIdentityName: 'dep-${namePrefix}-mi-${serviceShort}' + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}03' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + location: resourceLocation + } +} + +// ============== // +// Test Execution // +// ============== // + +@batchSize(1) +module testDeployment '../../../main.bicep' = [ + for iteration in ['init', 'idem']: { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-test-${serviceShort}-${iteration}' + params: { + name: '${namePrefix}${serviceShort}001' + location: resourceLocation + skuName: 'Balanced_B10' + database: { + clientProtocol: 'Plaintext' + clusteringPolicy: 'EnterpriseCluster' + deferUpgrade: 'Deferred' + evictionPolicy: 'NoEviction' + modules: [ + { + name: 'RedisBloom' + } + { + name: 'RediSearch' + } + ] + persistence: { + type: 'aof' + frequency: '1s' + } + diagnosticSettings: [ + { + name: 'customSettingDatabase' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + } + enableTelemetry: true + diagnosticSettings: [ + { + name: 'customSettingCluster' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + highAvailability: 'Disabled' + lock: { + kind: 'CanNotDelete' + name: 'myCustomLockName' + } + minimumTlsVersion: '1.2' + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + roleAssignments: [ + { + name: '759769d2-fc52-4a92-a943-724e48927e0b' + roleDefinitionIdOrName: 'Owner' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + name: guid('Custom seed ${namePrefix}${serviceShort}') + roleDefinitionIdOrName: 'b24988ac-6180-42a0-ab88-20f7382dd24c' + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + { + roleDefinitionIdOrName: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + 'acdd72a7-3385-48ef-bd42-f606fba81ae7' + ) + principalId: nestedDependencies.outputs.managedIdentityPrincipalId + principalType: 'ServicePrincipal' + } + ] + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + 3 + ] + } + } +] diff --git a/avm/res/cache/redis-enterprise/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep b/avm/res/cache/redis-enterprise/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep new file mode 100644 index 0000000000..b12458a9b8 --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/user-assigned-cmk-encryption/dependencies.bicep @@ -0,0 +1,63 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Managed Identity to create.') +param managedIdentityName string + +@description('Required. The name of the Key Vault to create.') +param keyVaultName string + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2018-11-30' = { + name: managedIdentityName + location: location +} + +resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' = { + name: keyVaultName + location: location + properties: { + sku: { + family: 'A' + name: 'standard' + } + tenantId: tenant().tenantId + enablePurgeProtection: true // Required for encryption to work + softDeleteRetentionInDays: 7 + enabledForTemplateDeployment: true + enabledForDiskEncryption: true + enabledForDeployment: true + enableRbacAuthorization: true + accessPolicies: [] + } + + resource key 'keys@2022-07-01' = { + name: 'keyEncryptionKey' + properties: { + kty: 'RSA' + } + } +} + +resource keyPermissions 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid('msi-${keyVault::key.id}-${location}-${managedIdentity.id}-Key-Key-Vault-Crypto-User-RoleAssignment') + scope: keyVault::key + properties: { + principalId: managedIdentity.properties.principalId + roleDefinitionId: subscriptionResourceId( + 'Microsoft.Authorization/roleDefinitions', + '12338af0-0e69-4776-bea7-57ae8d297424' + ) // Key Vault Crypto User + principalType: 'ServicePrincipal' + } +} +@description('The resource ID of the created Key Vault.') +output keyVaultResourceId string = keyVault.id + +@description('The name of the created Key Vault encryption key.') +output keyVaultKeyName string = keyVault::key.name + +@description('The resource ID of the created Managed Identity.') +output managedIdentityResourceId string = managedIdentity.id + +@description('The client ID of the created Managed Identity.') +output managedIdentityClientId string = managedIdentity.properties.clientId diff --git a/avm/res/cache/redis-enterprise/tests/e2e/user-assigned-cmk-encryption/main.test.bicep b/avm/res/cache/redis-enterprise/tests/e2e/user-assigned-cmk-encryption/main.test.bicep new file mode 100644 index 0000000000..77614d60c7 --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/user-assigned-cmk-encryption/main.test.bicep @@ -0,0 +1,75 @@ +targetScope = 'subscription' + +metadata name = 'Using Customer-Managed-Keys with User-Assigned identity' +metadata description = 'This instance deploys the module using Customer-Managed-Keys using a User-Assigned Identity to access the Customer-Managed-Key secret.' + +// ========== // +// Parameters // +// ========== // + +@description('Optional. The name of the resource group to deploy for testing purposes.') +@maxLength(90) +param resourceGroupName string = 'dep-${namePrefix}-cache-redisenterprise-${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 = 'creuace' + +@description('Generated. Used as a basis for unique resource names.') +param baseTime string = utcNow('u') + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2022-09-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + managedIdentityName: 'dep-${namePrefix}-msi-${serviceShort}' + // Adding base time to make the name unique as purge protection must be enabled (but may not be longer than 24 characters total) + keyVaultName: 'dep-${namePrefix}-kv-${serviceShort}-${substring(uniqueString(baseTime), 0, 3)}' + 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' + skuName: 'Balanced_B10' + customerManagedKey: { + keyName: nestedDependencies.outputs.keyVaultKeyName + keyVaultResourceId: nestedDependencies.outputs.keyVaultResourceId + userAssignedIdentityResourceId: nestedDependencies.outputs.managedIdentityResourceId + } + managedIdentities: { + userAssignedResourceIds: [ + nestedDependencies.outputs.managedIdentityResourceId + ] + } + database: { + persistence: { type: 'rdb', frequency: '6h' } + } + } + } +] diff --git a/avm/res/cache/redis-enterprise/tests/e2e/waf-aligned/dependencies.bicep b/avm/res/cache/redis-enterprise/tests/e2e/waf-aligned/dependencies.bicep new file mode 100644 index 0000000000..f4a2b05950 --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/waf-aligned/dependencies.bicep @@ -0,0 +1,49 @@ +@description('Optional. The location to deploy resources to.') +param location string = resourceGroup().location + +@description('Required. The name of the Virtual Network to create.') +param virtualNetworkName string + +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.redis.azure.net' + location: 'global' + + resource virtualNetworkLinks 'virtualNetworkLinks@2020-06-01' = { + name: '${virtualNetwork.name}-vnetlink' + location: 'global' + properties: { + virtualNetwork: { + id: virtualNetwork.id + } + registrationEnabled: false + } + } +} + +@description('The resource ID of the created Virtual Network Subnet.') +output subnetResourceId string = virtualNetwork.properties.subnets[0].id + +@description('The resource ID of the created Private DNS Zone.') +output privateDNSZoneResourceId string = privateDNSZone.id diff --git a/avm/res/cache/redis-enterprise/tests/e2e/waf-aligned/main.test.bicep b/avm/res/cache/redis-enterprise/tests/e2e/waf-aligned/main.test.bicep new file mode 100644 index 0000000000..a02bf8b192 --- /dev/null +++ b/avm/res/cache/redis-enterprise/tests/e2e/waf-aligned/main.test.bicep @@ -0,0 +1,132 @@ +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}-cache-redisenterprise-${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 = 'crewaf' + +@description('Optional. A token to inject into the name of each resource. This value can be automatically injected by the CI.') +param namePrefix string = '#_namePrefix_#' + +// ============ // +// Dependencies // +// ============ // + +// General resources +// ================= +resource resourceGroup 'Microsoft.Resources/resourceGroups@2021-04-01' = { + name: resourceGroupName + location: resourceLocation +} + +module nestedDependencies 'dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-nestedDependencies' + params: { + location: resourceLocation + virtualNetworkName: 'dep-${namePrefix}-vnet-${serviceShort}' + } +} + +// Diagnostics +// =========== +module diagnosticDependencies '../../../../../../../utilities/e2e-template-assets/templates/diagnostic.dependencies.bicep' = { + scope: resourceGroup + name: '${uniqueString(deployment().name, resourceLocation)}-diagnosticDependencies' + params: { + storageAccountName: 'dep${namePrefix}diasa${serviceShort}03' + logAnalyticsWorkspaceName: 'dep-${namePrefix}-law-${serviceShort}' + eventHubNamespaceEventHubName: 'dep-${namePrefix}-evh-${serviceShort}01' + eventHubNamespaceName: 'dep-${namePrefix}-evhns-${serviceShort}01' + 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' + diagnosticSettings: [ + { + name: 'customSettingCluster' + metricCategories: [ + { + category: 'AllMetrics' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + database: { + diagnosticSettings: [ + { + name: 'customSettingDatabase' + logCategoriesAndGroups: [ + { + categoryGroup: 'allLogs' + } + ] + eventHubName: diagnosticDependencies.outputs.eventHubNamespaceEventHubName + eventHubAuthorizationRuleResourceId: diagnosticDependencies.outputs.eventHubAuthorizationRuleId + storageAccountResourceId: diagnosticDependencies.outputs.storageAccountResourceId + workspaceResourceId: diagnosticDependencies.outputs.logAnalyticsWorkspaceResourceId + } + ] + persistence: { + type: 'rdb' + frequency: '1h' + } + } + privateEndpoints: [ + { + privateDnsZoneGroup: { + privateDnsZoneGroupConfigs: [ + { + privateDnsZoneResourceId: nestedDependencies.outputs.privateDNSZoneResourceId + } + ] + } + subnetResourceId: nestedDependencies.outputs.subnetResourceId + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + } + ] + skuName: 'Balanced_B10' + tags: { + 'hidden-title': 'This is visible in the resource name' + Environment: 'Non-Prod' + Role: 'DeploymentValidation' + } + zones: [ + 1 + 2 + 3 + ] + } + } +] diff --git a/avm/res/cache/redis-enterprise/version.json b/avm/res/cache/redis-enterprise/version.json new file mode 100644 index 0000000000..8def869ede --- /dev/null +++ b/avm/res/cache/redis-enterprise/version.json @@ -0,0 +1,7 @@ +{ + "$schema": "https://aka.ms/bicep-registry-module-version-file-schema#", + "version": "0.1", + "pathFilters": [ + "./main.json" + ] +}