Search code examples
azure-resource-managerazure-keyvaultazure-rm-template

The language expression property '0' can't be evaluated, property name must be a string - ARM Template error while adding Key Vault access policy


I've been working on an issue and seem to be stuck, so asking on so in case anyone can help.

To describe the issue, I've got an existing Azure Key Vault setup, and wish to add a number of access policies to this resource group. It needs to be conditional as if the function name is "false" then that function should not be added to key vault access policy.

variable section:

 "variables": {
    "functionAccess": {
      "value": [
        {
          "name": "[parameters('Function_1')]"
        },
        {
          "name": "[parameters('Function_2')]"
        },
        {
          "name": "[parameters('Function_3')]"
        }
      ]
    }
  }

My Template :

{
  "apiVersion": "2016-10-01",
  "condition": "[not(equals(variables('functionAccess')[CopyIndex()].name, 'false'))]",
  "copy": {
    "batchSize": 1,
    "count": "[length(variables('functionAccess'))]",
    "mode": "Serial",
    "name": "accessPolicies"
  },
  "name": "[concat(parameters('KeyVault_Name'), '/add')]",
  "properties": {
    "accessPolicies": [
      {
        "tenantId": "[subscription().tenantId]",
        "objectId": "[if(not(equals(variables('functionAccess')[CopyIndex()].name, 'false')), reference(concat('Microsoft.Web/sites/', variables('functionAccess')[CopyIndex()].name), '2016-08-01', 'Full').identity.principalId, json('null'))]",
        "permissions": {
          "keys": [
            "get",
            "list"
          ],
          "secrets": [
            "get",
            "list"
          ],
          "certificates": [
            "get",
            "list"
          ]
        }
      }
    ]
  },
  "type": "Microsoft.KeyVault/vaults/accessPolicies"
}

When I deploy my ARM template for the azure key vault I got this error message:

The language expression property '0' can't be evaluated, property name must be a string.

also tried below, but same error:

{
  "apiVersion": "2018-02-14",
  "name": "[concat(parameters('KeyVault_Name'), '/add')]",
  "properties": {
    "copy": [
      {
        "batchSize": 1,
        "count": "[length(variables('functionAccess'))]",
        "mode": "serial",
        "name": "accessPolicies",
        "input": {
          "condition": "[not(equals(variables('functionAccess')[copyIndex('accessPolicies')].name, 'false'))]",
          "tenantId": "[subscription().tenantId]",
          "objectId": "[if(not(equals(variables('functionAccess')[copyIndex('accessPolicies')].name, 'false')), reference(concat('Microsoft.Web/sites/', variables('functionAccess')[copyIndex('accessPolicies')].name), '2016-08-01', 'Full').identity.principalId, json('null'))]",
          "permissions": {
            "keys": [
              "get",
              "list"
            ],
            "secrets": [
              "get",
              "list"
            ],
            "certificates": [
              "get",
              "list"
            ]
          }
        }
      }
    ]
  },
  "type": "Microsoft.KeyVault/vaults/accessPolicies"
}

Solution

  • There are a few options for dealing with filtering an array for copy operation. I deploy my ARM templates from PowerShell scripts and use PowerShell to setup parameter values. When I need special logic handle different inputs for different environments, I let PowerShell handle it.

    If you must handle the filtering in ARM and you have the option to input a CSV list of functions, then perhaps the following will work. You can then use the functionAccessArray to iterate over in the copy operation.

    {
      "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
      "contentVersion": "1.0.0.0",
      "parameters": {
    
      },
      "variables": {
        "functionAccessCsv": "Function-0,Function-1,false,Function-4,false,Function-6,Function-7",
        "functionAccessFiltered": "[replace(replace(variables('functionAccessCsv'), 'false', ''), ',,', ',')]",
        "functionAccessArray": "[split(variables('functionAccessFiltered'), ',')]"
      },
      "resources": [
      ],
      "outputs": {
        "functionAccessCsvFiltered": {
          "type": "string",
          "value": "[variables('functionAccessFiltered')]"
        },
        "functionAccessArray": {
          "type": "array",
          "value": "[variables('functionAccessArray')]"
        }
      }
    }
    

    The result: enter image description here