How to assign System Managed Identities access to a Key Vault using a loop?

I have an array (variable) of virtual machine details that I use to deploy multiple virtual machines (using the copy element). Each of these virtual machines is using a System Managed Identity.

I want to grant each of these VMs access to a Key Vault. I have tried using a combination of the reference and resourceId functions. As per this example:

{
  "type": "Microsoft.KeyVault/vaults",
  "apiVersion": "2019-09-01",
  "name": "vaultName",
  "properties": {
    "tenantId": "[subscription().tenantId]",
    "accessPolicies": [
      {
        "tenantId": "[reference(resourceId('Microsoft.Compute/virtualMachines', variables('vmName')), '2019-03-01', 'Full').identity.tenantId]",
        "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines', variables('vmName')), '2019-03-01', 'Full').identity.principalId]",
        "permissions": {
          "keys": [
            "all"
          ],
          "secrets": [
            "all"
          ]
        }
      }
    ],
    ...

But I don't know how to get it to work in the loop. This does not work:

"variables": {
    "VMs": [
        {
            "name": "vm-test-dev-cace-001",
            "nicName": "nic-test-dev-cace-001",
            "privateIPAddress": "192.168.0.10",
            "zone": "1"
        },
        {
            "name": "vm-test-dev-cace-002",
            "nicName": "nic-test-dev-cace-002",
            "privateIPAddress": "192.168.0.11",
            "zone": "2"
        }
    ]

...

{
    "type": "Microsoft.KeyVault/vaults/accessPolicies",
    "name": "[concat(parameters('keyVaultName'), '/add')]",
    "location": "[parameters('resourcesLocation')]",
    "apiVersion": "2019-09-01",
    "properties": {
        "accessPolicies": [
            {
                "tenantId": "[subscription().tenantId]",
                "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines', variables('VMs')[0].name), '2019-03-01', 'Full').identity.principalId]",
                "keys": [],
                "permissions": {
                    "secrets": [
                        "get"
                    ],
                    "certificates": [
                        "get",
                        "list"
                    ]
                }
            }
        ]

Solution 1:

You can use the below code in your ARM template to create access policies for your VMs to access Key Vault

"properties": {
        "copy": [ {
               "name": "accessPolicies",
               "count": "[length(variables('VMs'))]",
               "input": {
                        "tenantId": "[subscription().tenantId]",
                        "objectId": "[reference(resourceId('Microsoft.Compute/virtualMachines', variables('VMs')[copyIndex('accessPolicies')].name), '2019-03-01', 'Full').identity.principalId]",
                        "keys": [],
                        "permissions": {
                             "secrets": [
                                    "get"
                                ],
                                "certificates": [
                                    "get",
                                    "list"
                                ]
                        }
                }
        } ]
}