Repository: Azure/bicep-registry-modules
Pull request #4733: feat: separate scope of storage account and key vault in azlocal
Author: login: xhy8759
Labels: name: Needs: Triage :mag:
description: Maintainers need to triage still
name: Type: AVM :a: :v: :m:
description: This is an AVM related issue
name: Needs: Module Owner :mega:
description: This module needs an owner to develop or maintain it
Created: 2025-03-13T07:37:56Z | Merged: 2025-03-13T08:55:01Z

## Description

<!--
>Thank you for your contribution !
> Please include a summary of the change and which issue is fixed.
> Please also include the context.
> List any dependencies that are required for this change.

Fixes #123
Fixes #456
Closes #123
Closes #456
-->

## Pipeline Reference

<!-- Insert your Pipeline Status Badge below -->

| Pipeline |
| -------- |
|          |

## Type of Change

<!-- Use the checkboxes [x] on the options that are relevant. -->

- [ ] Update to CI Environment or utilities (Non-module affecting changes)
- [ ] Azure Verified Module updates:
  - [ ] Bugfix containing backwards-compatible bug fixes, and I have NOT bumped the MAJOR or MINOR version in `version.json`:
    - [ ] Someone has opened a bug report issue, and I have included "Closes #{bug_report_issue_number}" in the PR description.
    - [ ] The bug was found by the module author, and no one has opened an issue to report it yet.
  - [ ] Feature update backwards compatible feature updates, and I have bumped the MINOR version in `version.json`.
  - [ ] Breaking changes and I have bumped the MAJOR version in `version.json`.
  - [ ] Update to documentation

## Checklist

- [ ] I'm sure there are no other open Pull Requests for the same update/change
- [ ] I have run `Set-AVMModule` locally to generate the supporting module files.
- [ ] My corresponding pipelines / checks run clean and green without any errors or warnings

<!--  Please keep up to date with the contribution guide at https://aka.ms/avm/contribute/bicep -->



Diff:
diff --git a/avm/res/azure-stack-hci/cluster/README.md b/avm/res/azure-stack-hci/cluster/README.md
index 23b95d01e61..dc33e33e084 100644
--- a/avm/res/azure-stack-hci/cluster/README.md
+++ b/avm/res/azure-stack-hci/cluster/README.md
@@ -937,12 +937,16 @@ param tags = {
 | [`deploymentOperations`](#parameter-deploymentoperations) | array | The cluster deployment operations to execute. Defaults to "[Validate, Deploy]". |
 | [`deploymentSettings`](#parameter-deploymentsettings) | object | The deployment settings of the cluster. |
 | [`enableTelemetry`](#parameter-enabletelemetry) | bool | Enable/Disable usage telemetry for module. |
+| [`keyvaultResourceGroup`](#parameter-keyvaultresourcegroup) | string | Key vault resource group, which is used for for storing secrets for the HCI cluster. |
+| [`keyvaultSubscriptionId`](#parameter-keyvaultsubscriptionid) | string | Key vault subscription ID, which is used for for storing secrets for the HCI cluster. |
 | [`localAdminCredentialContentType`](#parameter-localadmincredentialcontenttype) | string | Content type of the local admin credential. |
 | [`localAdminCredentialTags`](#parameter-localadmincredentialtags) | object | Tags of the local admin credential. |
 | [`location`](#parameter-location) | string | Location for all resources. |
 | [`roleAssignments`](#parameter-roleassignments) | array | Array of role assignments to create. |
 | [`tags`](#parameter-tags) | object | Tags of the resource. |
 | [`useSharedKeyVault`](#parameter-usesharedkeyvault) | bool | Specify whether to use the shared key vault for the HCI cluster. |
+| [`witnessStorageAccountResourceGroup`](#parameter-witnessstorageaccountresourcegroup) | string | Storage account resource group, which is used as the witness for the HCI Windows Failover Cluster. |
+| [`witnessStorageAccountSubscriptionId`](#parameter-witnessstorageaccountsubscriptionid) | string | Storage account subscription ID, which is used as the witness for the HCI Windows Failover Cluster. |
 | [`witnessStoragekeyContentType`](#parameter-witnessstoragekeycontenttype) | string | Content type of the witness storage key. |
 | [`witnessStoragekeyTags`](#parameter-witnessstoragekeytags) | object | Tags of the witness storage key. |
 
@@ -1079,7 +1083,6 @@ The deployment settings of the cluster.
 | :-- | :-- | :-- |
 | [`bitlockerBootVolume`](#parameter-deploymentsettingsbitlockerbootvolume) | bool | When set to true, BitLocker XTS_AES 256-bit encryption is enabled for all data-at-rest on the OS volume of your Azure Stack HCI cluster. This setting is TPM-hardware dependent. |
 | [`bitlockerDataVolumes`](#parameter-deploymentsettingsbitlockerdatavolumes) | bool | When set to true, BitLocker XTS-AES 256-bit encryption is enabled for all data-at-rest on your Azure Stack HCI cluster shared volumes. |
-| [`cloudId`](#parameter-deploymentsettingscloudid) | string | If using a shared key vault or non-legacy secret naming, pass the properties.cloudId guid from the pre-created HCI cluster resource. |
 | [`credentialGuardEnforced`](#parameter-deploymentsettingscredentialguardenforced) | bool | Enables the Credential Guard. |
 | [`driftControlEnforced`](#parameter-deploymentsettingsdriftcontrolenforced) | bool | When set to true, the security baseline is re-applied regularly. |
 | [`drtmProtection`](#parameter-deploymentsettingsdrtmprotection) | bool | The hardware-dependent Secure Boot setting. |
@@ -1213,13 +1216,6 @@ When set to true, BitLocker XTS-AES 256-bit encryption is enabled for all data-a
 - Required: No
 - Type: bool
 
-### Parameter: `deploymentSettings.cloudId`
-
-If using a shared key vault or non-legacy secret naming, pass the properties.cloudId guid from the pre-created HCI cluster resource.
-
-- Required: No
-- Type: string
-
 ### Parameter: `deploymentSettings.credentialGuardEnforced`
 
 Enables the Credential Guard.
@@ -1327,6 +1323,20 @@ Enable/Disable usage telemetry for module.
 - Type: bool
 - Default: `True`
 
+### Parameter: `keyvaultResourceGroup`
+
+Key vault resource group, which is used for for storing secrets for the HCI cluster.
+
+- Required: No
+- Type: string
+
+### Parameter: `keyvaultSubscriptionId`
+
+Key vault subscription ID, which is used for for storing secrets for the HCI cluster.
+
+- Required: No
+- Type: string
+
 ### Parameter: `localAdminCredentialContentType`
 
 Content type of the local admin credential.
@@ -1470,6 +1480,20 @@ Specify whether to use the shared key vault for the HCI cluster.
 - Type: bool
 - Default: `True`
 
+### Parameter: `witnessStorageAccountResourceGroup`
+
+Storage account resource group, which is used as the witness for the HCI Windows Failover Cluster.
+
+- Required: No
+- Type: string
+
+### Parameter: `witnessStorageAccountSubscriptionId`
+
+Storage account subscription ID, which is used as the witness for the HCI Windows Failover Cluster.
+
+- Required: No
+- Type: string
+
 ### Parameter: `witnessStoragekeyContentType`
 
 Content type of the witness storage key.
diff --git a/avm/res/azure-stack-hci/cluster/deployment-setting/README.md b/avm/res/azure-stack-hci/cluster/deployment-setting/README.md
index fa18c97ce31..cf58603b8b6 100644
--- a/avm/res/azure-stack-hci/cluster/deployment-setting/README.md
+++ b/avm/res/azure-stack-hci/cluster/deployment-setting/README.md
@@ -30,7 +30,7 @@ This module deploys an Azure Stack HCI Cluster Deployment Settings resource.
 | [`domainFqdn`](#parameter-domainfqdn) | string | The domain name of the Active Directory Domain Services. Example: "contoso.com". |
 | [`domainOUPath`](#parameter-domainoupath) | string | The ADDS OU path - ex "OU=HCI,DC=contoso,DC=com". |
 | [`endingIPAddress`](#parameter-endingipaddress) | string | The ending IP address for the Infrastructure Network IP pool. There must be at least 6 IPs between startingIPAddress and endingIPAddress and this pool should be not include the node IPs. |
-| [`keyVaultName`](#parameter-keyvaultname) | string | The name of the key vault to be used for storing secrets for the HCI cluster. This currently needs to be unique per HCI cluster. |
+| [`keyVaultName`](#parameter-keyvaultname) | string | The name of the key vault to be used for storing secrets for the HCI cluster. |
 | [`networkIntents`](#parameter-networkintents) | array | An array of Network ATC Network Intent objects that define the Compute, Management, and Storage network configuration for the cluster. |
 | [`startingIPAddress`](#parameter-startingipaddress) | string | The starting IP address for the Infrastructure Network IP pool. There must be at least 6 IPs between startingIPAddress and endingIPAddress and this pool should be not include the node IPs. |
 | [`storageConnectivitySwitchless`](#parameter-storageconnectivityswitchless) | bool | Specify whether the Storage Network connectivity is switched or switchless. |
@@ -144,7 +144,7 @@ The ending IP address for the Infrastructure Network IP pool. There must be at l
 
 ### Parameter: `keyVaultName`
 
-The name of the key vault to be used for storing secrets for the HCI cluster. This currently needs to be unique per HCI cluster.
+The name of the key vault to be used for storing secrets for the HCI cluster.
 
 - Required: Yes
 - Type: string
diff --git a/avm/res/azure-stack-hci/cluster/deployment-setting/main.bicep b/avm/res/azure-stack-hci/cluster/deployment-setting/main.bicep
index d7fb08a8858..4bb6e2cd730 100644
--- a/avm/res/azure-stack-hci/cluster/deployment-setting/main.bicep
+++ b/avm/res/azure-stack-hci/cluster/deployment-setting/main.bicep
@@ -117,7 +117,7 @@ param customLocationName string
 @description('Required. The name of the storage account to be used as the witness for the HCI Windows Failover Cluster.')
 param clusterWitnessStorageAccountName string
 
-@description('Required. The name of the key vault to be used for storing secrets for the HCI cluster. This currently needs to be unique per HCI cluster.')
+@description('Required. The name of the key vault to be used for storing secrets for the HCI cluster.')
 param keyVaultName string
 
 @description('Optional. If using a shared key vault or non-legacy secret naming, pass the properties.cloudId guid from the pre-created HCI cluster resource.')
diff --git a/avm/res/azure-stack-hci/cluster/deployment-setting/main.json b/avm/res/azure-stack-hci/cluster/deployment-setting/main.json
index 2edb982bfa3..49aab2c7180 100644
--- a/avm/res/azure-stack-hci/cluster/deployment-setting/main.json
+++ b/avm/res/azure-stack-hci/cluster/deployment-setting/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.33.93.31351",
-      "templateHash": "7982158538530558379"
+      "templateHash": "9536857013030923630"
     },
     "name": "Azure Stack HCI Cluster Deployment Settings",
     "description": "This module deploys an Azure Stack HCI Cluster Deployment Settings resource."
@@ -242,7 +242,7 @@
     "keyVaultName": {
       "type": "string",
       "metadata": {
-        "description": "Required. The name of the key vault to be used for storing secrets for the HCI cluster. This currently needs to be unique per HCI cluster."
+        "description": "Required. The name of the key vault to be used for storing secrets for the HCI cluster."
       }
     },
     "cloudId": {
diff --git a/avm/res/azure-stack-hci/cluster/main.bicep b/avm/res/azure-stack-hci/cluster/main.bicep
index f952b71f3d9..86358870194 100644
--- a/avm/res/azure-stack-hci/cluster/main.bicep
+++ b/avm/res/azure-stack-hci/cluster/main.bicep
@@ -81,6 +81,18 @@ param witnessStoragekeyTags object?
 @description('Optional. Tags of the default ARB application.')
 param defaultARBApplicationTags object?
 
+@description('Optional. Key vault subscription ID, which is used for for storing secrets for the HCI cluster.')
+param keyvaultSubscriptionId string?
+
+@description('Optional. Key vault resource group, which is used for for storing secrets for the HCI cluster.')
+param keyvaultResourceGroup string?
+
+@description('Optional. Storage account subscription ID, which is used as the witness for the HCI Windows Failover Cluster.')
+param witnessStorageAccountSubscriptionId string?
+
+@description('Optional. Storage account resource group, which is used as the witness for the HCI Windows Failover Cluster.')
+param witnessStorageAccountResourceGroup string?
+
 // ============= //
 //   Variables   //
 // ============= //
@@ -160,6 +172,10 @@ resource cluster 'Microsoft.AzureStackHCI/clusters@2024-04-01' = {
 
 module secrets './secrets.bicep' = if (useSharedKeyVault) {
   name: '${uniqueString(deployment().name, location)}-secrets'
+  scope: resourceGroup(
+    keyvaultSubscriptionId ?? subscription().subscriptionId,
+    keyvaultResourceGroup ?? resourceGroup().name
+  )
   params: {
     clusterName: name
     cloudId: cluster.properties.cloudId
@@ -179,6 +195,8 @@ module secrets './secrets.bicep' = if (useSharedKeyVault) {
     localAdminCredentialTags: localAdminCredentialTags
     witnessStoragekeyTags: witnessStoragekeyTags
     defaultARBApplicationTags: defaultARBApplicationTags
+    witnessStorageAccountResourceGroup: witnessStorageAccountResourceGroup ?? resourceGroup().name
+    witnessStorageAccountSubscriptionId: witnessStorageAccountSubscriptionId ?? subscription().subscriptionId
   }
 }
 
@@ -469,9 +487,6 @@ type deploymentSettingsType = {
 
   @description('Required. The name of the key vault to be used for storing secrets for the HCI cluster. This currently needs to be unique per HCI cluster.')
   keyVaultName: string
-
-  @description('Optional. If using a shared key vault or non-legacy secret naming, pass the properties.cloudId guid from the pre-created HCI cluster resource.')
-  cloudId: string?
 }
 
 @export()
diff --git a/avm/res/azure-stack-hci/cluster/main.json b/avm/res/azure-stack-hci/cluster/main.json
index 47a732270e5..fcb65150c8f 100644
--- a/avm/res/azure-stack-hci/cluster/main.json
+++ b/avm/res/azure-stack-hci/cluster/main.json
@@ -6,7 +6,7 @@
     "_generator": {
       "name": "bicep",
       "version": "0.33.93.31351",
-      "templateHash": "5165165585899213815"
+      "templateHash": "3963124488380176930"
     },
     "name": "Azure Stack HCI Cluster",
     "description": "This module deploys an Azure Stack HCI Cluster on the provided Arc Machines."
@@ -484,13 +484,6 @@
           "metadata": {
             "description": "Required. The name of the key vault to be used for storing secrets for the HCI cluster. This currently needs to be unique per HCI cluster."
           }
-        },
-        "cloudId": {
-          "type": "string",
-          "nullable": true,
-          "metadata": {
-            "description": "Optional. If using a shared key vault or non-legacy secret naming, pass the properties.cloudId guid from the pre-created HCI cluster resource."
-          }
         }
       }
     },
@@ -771,6 +764,34 @@
       "metadata": {
         "description": "Optional. Tags of the default ARB application."
       }
+    },
+    "keyvaultSubscriptionId": {
+      "type": "string",
+      "nullable": true,
+      "metadata": {
+        "description": "Optional. Key vault subscription ID, which is used for for storing secrets for the HCI cluster."
+      }
+    },
+    "keyvaultResourceGroup": {
+      "type": "string",
+      "nullable": true,
+      "metadata": {
+        "description": "Optional. Key vault resource group, which is used for for storing secrets for the HCI cluster."
+      }
+    },
+    "witnessStorageAccountSubscriptionId": {
+      "type": "string",
+      "nullable": true,
+      "metadata": {
+        "description": "Optional. Storage account subscription ID, which is used as the witness for the HCI Windows Failover Cluster."
+      }
+    },
+    "witnessStorageAccountResourceGroup": {
+      "type": "string",
+      "nullable": true,
+      "metadata": {
+        "description": "Optional. Storage account resource group, which is used as the witness for the HCI Windows Failover Cluster."
+      }
     }
   },
   "variables": {
@@ -851,6 +872,8 @@
       "type": "Microsoft.Resources/deployments",
       "apiVersion": "2022-09-01",
       "name": "[format('{0}-secrets', uniqueString(deployment().name, parameters('location')))]",
+      "subscriptionId": "[coalesce(parameters('keyvaultSubscriptionId'), subscription().subscriptionId)]",
+      "resourceGroup": "[coalesce(parameters('keyvaultResourceGroup'), resourceGroup().name)]",
       "properties": {
         "expressionEvaluationOptions": {
           "scope": "inner"
@@ -910,6 +933,12 @@
           },
           "defaultARBApplicationTags": {
             "value": "[parameters('defaultARBApplicationTags')]"
+          },
+          "witnessStorageAccountResourceGroup": {
+            "value": "[coalesce(parameters('witnessStorageAccountResourceGroup'), resourceGroup().name)]"
+          },
+          "witnessStorageAccountSubscriptionId": {
+            "value": "[coalesce(parameters('witnessStorageAccountSubscriptionId'), subscription().subscriptionId)]"
           }
         },
         "template": {
@@ -920,7 +949,7 @@
             "_generator": {
               "name": "bicep",
               "version": "0.33.93.31351",
-              "templateHash": "10708445161227912080"
+              "templateHash": "5238695736774441169"
             }
           },
           "parameters": {
@@ -1039,6 +1068,18 @@
               "metadata": {
                 "description": "Optional. Tags of the default ARB application."
               }
+            },
+            "witnessStorageAccountSubscriptionId": {
+              "type": "string",
+              "metadata": {
+                "description": "Optional. Storage account subscription ID, which is used as the witness for the HCI Windows Failover Cluster."
+              }
+            },
+            "witnessStorageAccountResourceGroup": {
+              "type": "string",
+              "metadata": {
+                "description": "Optional. Storage account resource group, which is used as the witness for the HCI Windows Failover Cluster.."
+              }
             }
           },
           "resources": {
@@ -1046,6 +1087,8 @@
               "existing": true,
               "type": "Microsoft.Storage/storageAccounts",
               "apiVersion": "2023-01-01",
+              "subscriptionId": "[parameters('witnessStorageAccountSubscriptionId')]",
+              "resourceGroup": "[parameters('witnessStorageAccountResourceGroup')]",
               "name": "[parameters('storageAccountName')]"
             },
             "keyVault": {
@@ -1086,7 +1129,7 @@
               "name": "[format('{0}/{1}', parameters('keyVaultName'), format('{0}-WitnessStorageKey-{1}', parameters('clusterName'), parameters('cloudId')))]",
               "properties": {
                 "contentType": "[parameters('witnessStoragekeyContentType')]",
-                "value": "[base64(listKeys(resourceId('Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2023-01-01').keys[0].value)]",
+                "value": "[base64(listKeys(extensionResourceId(format('/subscriptions/{0}/resourceGroups/{1}', parameters('witnessStorageAccountSubscriptionId'), parameters('witnessStorageAccountResourceGroup')), 'Microsoft.Storage/storageAccounts', parameters('storageAccountName')), '2023-01-01').keys[0].value)]",
                 "attributes": {
                   "enabled": true
                 }
@@ -1236,7 +1279,7 @@
             "_generator": {
               "name": "bicep",
               "version": "0.33.93.31351",
-              "templateHash": "7982158538530558379"
+              "templateHash": "9536857013030923630"
             },
             "name": "Azure Stack HCI Cluster Deployment Settings",
             "description": "This module deploys an Azure Stack HCI Cluster Deployment Settings resource."
@@ -1472,7 +1515,7 @@
             "keyVaultName": {
               "type": "string",
               "metadata": {
-                "description": "Required. The name of the key vault to be used for storing secrets for the HCI cluster. This currently needs to be unique per HCI cluster."
+                "description": "Required. The name of the key vault to be used for storing secrets for the HCI cluster."
               }
             },
             "cloudId": {
diff --git a/avm/res/azure-stack-hci/cluster/secrets.bicep b/avm/res/azure-stack-hci/cluster/secrets.bicep
index 24d5d20f34c..dccf0deb9e0 100644
--- a/avm/res/azure-stack-hci/cluster/secrets.bicep
+++ b/avm/res/azure-stack-hci/cluster/secrets.bicep
@@ -55,8 +55,15 @@ param witnessStoragekeyTags object?
 @description('Optional. Tags of the default ARB application.')
 param defaultARBApplicationTags object?
 
+@description('Optional. Storage account subscription ID, which is used as the witness for the HCI Windows Failover Cluster.')
+param witnessStorageAccountSubscriptionId string
+
+@description('Optional. Storage account resource group, which is used as the witness for the HCI Windows Failover Cluster..')
+param witnessStorageAccountResourceGroup string
+
 resource witnessStorageAccount 'Microsoft.Storage/storageAccounts@2023-01-01' existing = {
   name: storageAccountName
+  scope: resourceGroup(witnessStorageAccountSubscriptionId, witnessStorageAccountResourceGroup)
 }
 
 resource keyVault 'Microsoft.KeyVault/vaults@2022-07-01' existing = {


Reviews:
user: login: nasusoba
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-13T07:56:39Z
user: login: nasusoba
state: COMMENTED
author_association: NONE
submitted_at: 2025-03-13T08:34:05Z
user: login: nasusoba
state: DISMISSED
author_association: NONE
submitted_at: 2025-03-13T08:38:50Z
user: login: nasusoba
state: APPROVED
author_association: NONE
submitted_at: 2025-03-13T08:51:01Z

Review comments:
diff_hunk: @@ -81,6 +81,18 @@ param witnessStoragekeyTags object?
 @description('Optional. Tags of the default ARB application.')
 param defaultARBApplicationTags object?
 
+@description('Optional. Key vault subscription ID.')
+param kvSubscriptionId string?
+
+@description('Optional. Key vault resource group.')
+param kvResourceGroup string?
+
+@description('Optional. Storage account subscription ID.')
+param storageAccountSubscriptionId string?
+
+@description('Optional. Storage account resource group.')
+param storageAccountResourceGroup string?
path: avm/res/azure-stack-hci/cluster/main.bicep
user: login: nasusoba
body: `witnessStorageAccountResourceGroupName` might be better? Could also add more descriptions
created_at: 2025-03-13T07:56:33Z
author_association: NONE
diff_hunk: @@ -81,6 +81,18 @@ param witnessStoragekeyTags object?
 @description('Optional. Tags of the default ARB application.')
 param defaultARBApplicationTags object?
 
+@description('Optional. Key vault subscription ID, which is used for for storing secrets for the HCI cluster.')
+param keyvaultSubscriptionId string?
+
+@description('Optional. Key vault resource group, which is used for for storing secrets for the HCI cluster.')
+param keyvaultResourceGroup string?
+
+@description('Optional. Storage account subscription ID, which is used as the witness for the HCI Windows Failover Cluster.')
+param storageAccountSubscriptionId string?
+
+@description('Optional. Storage account resource group, which is used as the witness for the HCI Windows Failover Cluster..')
path: avm/res/azure-stack-hci/cluster/main.bicep
user: login: nasusoba
body: minor: `.` is typed twice (at the end)
created_at: 2025-03-13T08:31:39Z
author_association: NONE

PR comments:
user: login: microsoft-github-policy-service[bot]
created_at: 2025-03-13T07:38:48Z
body: > [!IMPORTANT]
> **The "Needs: Triage :mag:" label must be removed once the triage process is complete!**

> [!TIP]
> For additional guidance on how to triage this issue/PR, see the [BRM Issue Triage](https://azure.github.io/Azure-Verified-Modules/help-support/issue-triage/brm-issue-triage/) documentation.

<!-- Policy app identification https://img.shields.io/static/v1?label=PullRequestIssueManagement. -->
author_association: NONE
user: login: microsoft-github-policy-service[bot]
created_at: 2025-03-13T07:38:49Z
body: > [!IMPORTANT]
> If this is a module-related PR, being submitted by the sole owner of the module, the AVM core team must review and approve it (as module owners can't approve their own PRs).
>
> **To indicate this PR needs the core team''s attention, apply the "Needs: Core Team 🧞" label!**
>
> The core team will only review and approve PRs that have this label applied!

<!-- Policy app identification https://img.shields.io/static/v1?label=PullRequestIssueManagement. -->
author_association: NONE