如何有条件地为具有ARM模板副本的存储帐户提供N个角色分配



我正在尝试配置N个存储帐户,N个角色分配(每个存储帐户1个(,授予对特定身份的访问权限,但仅有条件地部署角色分配。存储帐户和标识已经存在,它们的模板逻辑已经运行了一段时间。

如果我尝试部署下面的模板片段;语言表达式属性数组索引"0"越界;关于"[concat(parameters('BackupStorageAccountRoleAssignmentsDeployment'([0].AccountName,'/Microsoft.Authentication/',guid(parameter('Backup StorageAccountRoleassignmentsDeployment]([0].Name(]'"当角色分配的输入数组为空时。

我已经在使用技巧来强制0长度的副本为length=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)]"
}
}
]
}
}
}

零长度数组上的复制循环问题是已知的,微软团队已经在路线图上解决了这个问题。

目前的解决方案是将循环移动到嵌套部署中,将数组作为参数传递,并检查该嵌套部署是否为空。尽管我不确定部署是否必须是内部范围的。当然,它将在变量范围设置为内部的情况下工作。

所以有几种方法可以解决这个问题。我很难得到米克的建议,按照我想要的方式工作。不过,我确实找到了另一个变通办法;在模板中使用变量以确保输入数组是ALWAY填充的

注:

  • 正则"defaultValue"属性不起作用,如果传递了空数组,则不会应用默认值。您需要使用一些if块来计算单个元素数组,作为非操作部署的默认值

  • ARM将模板扩展到";编译";时间所以你得到了";0越界";错误基于模板的替换值,而不是在实际部署开始时。问题是我试图使用零长度的副本,并且我在特殊的ARM函数/项(如referencedependsOn(中引用了copyindex()

{
"$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"
},
"Enabled": {
"type: "bool"
}
},
"variables": {
"IdentityResourceId": "[resourceId('Microsoft.ManagedIdentity/userAssignedIdentities', parameters('IdentityName'))]",
"ComputedRoleAssignments": "[if(greater(length(parameters('RoleAssignments')), 0), 
parameters('RoleAssignments'), 
createArray(createObject('AccountName', 'dummy', 'Name', 'dummy', 'ResourceId', 'dummy', 'RoleDefinitionId', 'dummy', 'PrincipalType', 'dummy', 'Scope', 'dummy', 'PrincipalId', 'dummy')))]"
},
"resources": [
{ // Everything related to role assignments chokes completely, even if I unroll the loop
"dependsOn": [
"[variables('IdentityResourceId')]",
"storageaccountcopy"
],
"copy": {
"name": "RoleAssignmentsCopy",
"count": "[length(variables('ComputedRoleAssignments'))]"
}, // Conditionally deploy based on parameters, but use the value from computed variables
"condition": "[and(greater(length(parameters('RoleAssignments')), 0), parameters('Enabled'))]",
"type": "Microsoft.Storage/storageAccounts/providers/roleAssignments",
"apiVersion": "2020-04-01-preview",
"name": "[concat(variables('ComputedRoleAssignments')[copyIndex()].AccountName, '/Microsoft.Authorization/', guid(variables('ComputedRoleAssignments')[copyIndex()].Name))]",
"properties": {
"roleDefinitionId": "[variables('ComputedRoleAssignments')[copyIndex()].RoleDefinitionId]",
"principalId": "[if(and(empty(parameters('ComputedRoleAssignments')[copyIndex()].ResourceId), not(empty(parameters('ComputedRoleAssignments')[copyIndex()].PrincipalId))), 
variables('ComputedRoleAssignments')[copyIndex()].PrincipalId, 
reference(variables('ComputedRoleAssignments')[copyIndex()].ResourceId, '2018-11-30').PrincipalId)]",
"scope": "[variables('ComputedRoleAssignments')[copyIndex()].Scope]",
"principalType": "[variables('ComputedRoleAssignments')[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"
}
}
}
]
}

最新更新