首页 > 解决方案 > 如何使用 ARM 模板副本有条件地为存储帐户提供 N 个角色分配?

问题描述

我正在尝试提供 N 个存储帐户、N 个角色分配(每个存储帐户 1 个)来授予对特定身份的访问权限,但只能有条件地部署角色分配。存储帐户和身份已经存在,并且它们的模板逻辑已经工作了一段时间。

如果我尝试部署以下模板片段,我会在“[concat(parameters('BackupStorageAccountRoleAssignmentsDeployment')[0].AccountName, '/Microsoft.Authorization /', guid(parameters('BackupStorageAccountRoleAssignmentsDeployment')[0].Name))]'" 当角色分配的输入数组为空时。

我已经在使用技巧将长度为 0 的副本强制为长度 = 1,然后在某个条件下保护部署。我尝试了使用大小为 1 的默认数组的变体,将我的角色分配部分移动到一个嵌套模板中,并手动将我的循环展开为 4 个角色分配。无论如何,我遇到了同样的错误。这个片段有什么问题?

{
    "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
    "contentVersion": "1.0.0.0",
    "parameters": {
        "RoleAssignments": {
            "type": "array"
        },
        "IdentityName": {
            "type": "string"
        },
        "StorageAccounts": {
            "type": "array"
        }
    },
    "variables": {
        "IdentityResourceId": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('IdentityName'))]"
    },
    "resources": [
        { // Everything related to role assignments chokes completely, even if I unroll the loop
            "dependsOn": [
                "[variables('IdentityResourceId')]",
                "storageaccountcopy"
            ],
            "copy": {
                "name": "RoleAssignmentsCopy",
                "count": "[max(length(parameters('BackupStorageAccountRoleAssignmentsDeployment')), 1)]"
            },
            "condition": "[greater(length(parameters('RoleAssignments')), 0)]",
            "type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
            "apiVersion": "2020-04-01-preview",
            "name": "[concat(parameters('RoleAssignments')[copyIndex()].AccountName, '/Microsoft.Authorization/', guid(parameters('RoleAssignments')[copyIndex()].Name))]",
            "properties": {
                "roleDefinitionId": "[parameters('RoleAssignments')[copyIndex()].RoleDefinitionId]",
                "principalId": "[if(and(empty(parameters('RoleAssignments')[copyIndex()].ResourceId), not(empty(parameters('RoleAssignments')[copyIndex()].PrincipalId))), 
                                parameters('RoleAssignments')[copyIndex()].PrincipalId, 
                                reference(parameters('RoleAssignments')[copyIndex()].ResourceId, '2018-11-30').PrincipalId)]",
                "scope": "[parameters('RoleAssignments')[copyIndex()].Scope]",
                "principalType": "[parameters('RoleAssignments')[copyIndex()].PrincipalType]"
            }
        },
        {   // Everthing related to storage account provisioning works fine, this was existing code
            "condition": "[and(greater(length(parameters('StorageAccounts')), 0), not(parameters('SkipStorageAccountProvisioning')), equals(parameters('StorageAccountProvisioningDefault'), 'true'))]",
            "copy": {
                "name": "storageaccountcopy",
                "count": "[length(parameters('StorageAccounts'))]"
            },
            "type": "Microsoft.Storage/storageAccounts",
            "apiVersion": "2019-06-01",
            "name": "[parameters('StorageAccounts')[copyIndex()].AccountName]",
            "location": "[resourceGroup().location]",
            "sku": {
                "name": "[if(equals(parameters('StorageAccounts')[copyIndex()].AccountTypeOverride, parameters('StorageAccountTypeOverrideDefault')), parameters('StorageAccounts')[copyIndex()].AccountType, parameters('StorageAccounts')[copyIndex()].AccountTypeOverride)]",
                "tier": "Standard"
            },
            "kind": "[parameters('StorageAccounts')[copyIndex()].AccountKind]",
            "properties": {
                "networkAcls": {
                    "bypass": "AzureServices",
                    "virtualNetworkRules": [],
                    "ipRules": [],
                    "defaultAction": "Allow"
                },
                "supportsHttpsTrafficOnly": true,
                "encryption": {
                    "services": {
                        "file": {
                            "keyType": "Account",
                            "enabled": true
                        },
                        "blob": {
                            "keyType": "Account",
                            "enabled": true
                        }
                    },
                    "keySource": "Microsoft.Storage"
                }
            }
        }
    ]
}

编辑:

根据反馈,我尝试将片段移动到嵌套模板中。以完全相同的错误失败,The template resource '[concat(parameters('RoleAssignments')[copyIndex()].AccountName, '/Microsoft.Authorization/', guid(parameters('BackupStorageAccountRoleAssignments')[copyIndex()].Name))]' at line '1' and column '837' is not valid: The language expression property array index '0' is out of bounds..

{
      "dependsOn": [
        "[variables('IdentityResourceId')]"
      ],
      "type": "Microsoft.Resources/deployments",
      "apiVersion": "2020-10-01",
      "name": "RoleAssignmentsDeployment",
      "properties": {
        "mode": "Incremental",
        "expressionEvaluationOptions": {
          "scope": "inner"
        },
        "parameters": {
          "RoleAssignments": {
            "value": "[parameters('RoleAssignmentsDeployment')]"
          }
        },
        "template": {
          "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
          "contentVersion": "1.0.0.0",
          "parameters": {
            "RoleAssignments": {
              "type": "array"
            }
          },
          "resources": [
            {
              "dependsOn": [
                "[resourceId('Microsoft.Storage/storageAccounts', parameters('RoleAssignments')[copyIndex()].AccountName)]"
              ],
              "copy": {
                "name": "RoleAssignmentsDeploymentCopy",
                "count": "[max(length(parameters('RoleAssignments')), 1)]"
              },
              "condition": "[greater(length(parameters('RoleAssignments')), 0)]",
              "type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
              "apiVersion": "2020-10-01",
              "name": "[concat(parameters('RoleAssignments')[copyIndex()].AccountName, '/Microsoft.Authorization/', guid(parameters('RoleAssignments')[copyIndex()].Name))]",
              "properties": {
                "scope": "[parameters('RoleAssignments')[copyIndex()].Scope]",
                "principalType": "[parameters('RoleAssignments')[copyIndex()].PrincipalType]",
                "roleDefinitionId": "[parameters('RoleAssignments')[copyIndex()].RoleDefinitionId]",

                "principalId": "[if(and(empty(parameters('RoleAssignments')[copyIndex()].ResourceId), not(empty(parameters('RoleAssignments')[copyIndex()].PrincipalId))), 
                                    parameters('RoleAssignments')[copyIndex()].PrincipalId, 
                                    reference(parameters('RoleAssignments')[copyIndex()].ResourceId, '2020-10-01').PrincipalId)]"
              }
            }
          ]
        }
      }
    }

标签: azureazure-resource-managerarm-template

解决方案


已知零长度数组上的复制循环问题,微软团队已在其路线图上修复它。

目前的解决方案是将循环移动到嵌套部署中,将数组作为参数传递,并通过检查数组是否为空来判断嵌套部署的条件。虽然我不确定部署是否必须在内部范围内。当然,它可以与设置为内部的变量范围一起工作。


推荐阅读