Azure 托管 ID - 如何通过 shell 分配多个 RBAC 角色

Azure Managed ID - How to assign Multiple RBAC Roles via shell

背景信息

我有以下将 RBAC 分配给托管 ID 的 arm 模板;

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "principalId": {
      "type": "string",
      "metadata": {
        "description": "The principal to assign the role to"
      }
    },
    "builtInRoleType": {
      "type": "string",
      "allowedValues": [
        "Owner",
        "Contributor",
        "Reader",
        "StorageQueueDataContributor",
        "StorageTableDataContributor"
      ],
      "metadata": {
        "description": "Built-in role to assign"
      }
    },
    "roleNameGuid": {
      "type": "string",
      "defaultValue": "[newGuid()]",
      "metadata": {
        "description": "A new GUID used to identify the role assignment"
      }
    }
  },
  "variables": {
    "Owner": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]",
    "Contributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
    "Reader": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]",
    "StorageQueueDataContributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/','974c5e8b-45b9-4653-ba55-5f855dd0fb88')]",
    "StorageTableDataContributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/','0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]"
  },
  "resources": [
    {
      "type": "Microsoft.Authorization/roleAssignments",
      "apiVersion": "2018-09-01-preview",
      "name": "[parameters('roleNameGuid')]",
      "properties": {
        "roleDefinitionId": "[variables(parameters('builtInRoleType'))]",
        "principalId": "[parameters('principalId')]"
      }
    }
  ]
}

我从这样的 powershell 脚本中调用它:

az deployment group create `
    --resource-group $RESOURCE_GROUP `
    --template-file "./rbac-role.json" `
    --parameters principalId=$objectid builtInRoleType=StorageTableDataContributor roleNameGuid=0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3

到目前为止一切顺利。但现在我希望能够分配多个 RBAC 角色,而不是一个。我尝试调用它两次,每个角色类型调用一次,但失败并出现错误:

{"status":"Failed","error":{"code":"DeploymentFailed","message":"At least one resource deployment operation failed. Please list deployment operations for details. Please see https://aka.ms/DeployOperations for usage details.","details":[{"code":"BadRequest","message":"{\r\n  \"error\": {\r\n    \"code\": \"RoleAssignmentUpdateNotPermitted\",\r\n    \"message\": \"Tenant ID, application ID, principal ID, and scope are not allowed to be updated.\"\r\n  }\r\n}"}]}}

到目前为止我已经尝试过什么

我试过将数组作为参数传递。在阅读文档时,似乎 ARM 模板参数可以接受数组。
所以我更新了我的 powershell 代码,如下所示:

$RoleTypeArray = @(
    'StorageQueueDataContributor'
    'StorageTableDataContributor'
)
$RoleGuidArray = @(
    '974c5e8b-45b9-4653-ba55-5f855dd0fb88'
    '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3'
)

az deployment group create `
    --resource-group $RESOURCE_GROUP `
    --template-file "./rbac-role.json" `
    --parameters principalId=$objectid builtInRoleType=$RoleTypeArray roleNameGuid=$RoleGuidArray

模板如下:

{
  "$schema": "https://schema.management.azure.com/schemas/2015-01-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "principalId": {
      "type": "string",
      "metadata": {
        "description": "The principal to assign the role to"
      }
    },
    "builtInRoleType": {
      "type": "array",
      "defaultValue": [
        "Owner",
        "Contributor",
        "Reader",
        "StorageQueueDataContributor",
        "StorageTableDataContributor"
      ],
      "metadata": {
        "description": "Built-in role to assign"
      }
    },
    "roleNameGuid": {
      "type": "array",
      "defaultValue": [
        "8e3af657-a8ff-443c-a75c-2fe8c4bcb635",
        "b24988ac-6180-42a0-ab88-20f7382dd24c",
        "acdd72a7-3385-48ef-bd42-f606fba81ae7",
        "974c5e8b-45b9-4653-ba55-5f855dd0fb88",
        "0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3"
      ],
      "metadata": {
        "description": "A new GUID used to identify the role assignment"
      }
    }
  },
  "variables": {
    "Owner": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]",
    "Contributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
    "Reader": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]",
    "StorageQueueDataContributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/','974c5e8b-45b9-4653-ba55-5f855dd0fb88')]",
    "StorageTableDataContributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/','0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]"
  },
  "resources": [
    {
      "type": "Microsoft.Authorization/roleAssignments",
      "apiVersion": "2018-09-01-preview",
      "name": "[parameters('roleNameGuid')[0]]",
      "properties": {
        "roleDefinitionId": "[variables(parameters('builtInRoleType')[0])]",
        "principalId": "[parameters('principalId')]"
      }
    }
  ]
}

现在,我只是将索引硬编码为 0,但如果这是正确的树,我将不得不弄清楚如何循环?或者我可以在 JSON ARM 模板文件中创建相同的部分两次 - 两个角色各一次?

目前,我得到的错误是:

Failed to parse JSON: StorageQueueDataContributor StorageTableDataContributor
Error detail: Expecting value: line 1 column 1 (char 0)

我不清楚它什么时候死了。 添加一些调试语句,但如有任何提示,我们将不胜感激。

编辑 1

我已将我的 ARM 模板修改为如下所示:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "principalId": {
      "type": "string",
      "metadata": {
        "description": "The principal to assign the role to"
      }
    },
    "builtInRoleType": {
      "type": "array",
      "defaultValue": [
        "Owner",
        "Contributor",
        "Reader",
        "StorageQueueDataContributor",
        "StorageTableDataContributor"
      ],
      "metadata": {
        "description": "Built-in role to assign"
      }
    }
  },
  "variables": {
    "Owner": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635')]",
    "Contributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'b24988ac-6180-42a0-ab88-20f7382dd24c')]",
    "Reader": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/', 'acdd72a7-3385-48ef-bd42-f606fba81ae7')]",
    "StorageQueueDataContributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/','974c5e8b-45b9-4653-ba55-5f855dd0fb88')]",
    "StorageTableDataContributor": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/','0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3')]"
  },
  "resources": [
    {
      "copy": {
        "name": "roleAssignment",
        "count": "[length(parameters('builtInRoleType'))]"
      },
      "type": "Microsoft.Authorization/roleAssignments",
      "apiVersion": "2018-09-01-preview",
      "name": "[guid(subscription().subscriptionId, resourceGroup().name, parameters('builtInRoleType')[copyIndex()], parameters('principalId'))]",
      "properties": {
        "roleDefinitionId": "[parameters('builtInRoleType')[copyIndex()]]",
        "principalId": "[parameters('principalId')]"
      }
    }
  ]
}

我是这样称呼它的:

az deployment group create `
    --resource-group $RESOURCE_GROUP_NAME `
    --template-file "./rbac-role.json" `
    --parameters `
    principalId=$objectid `
    builtInRoleType="['StorageQueueDataContributor', 'StorageTableDataContributor']"

但我得到的错误是

{
    "status": "Failed",
    "error": {
        "code": "BadRequestFormat",
        "message": "The request was incorrectly formatted."
    }
}

我认为这可能与 roleDefinitionID 有关。 这是我第二次测试重构后的代码。虽然第一次通过,roleDefinitionID 仍然看起来像这样:

    "roleDefinitionId": "[variables(parameters('builtInRoleType')[0])]",
    "principalId": "[parameters('principalId')]"

我最终将 StorageQueueDataContributor 角色分配了两次。

这里有很多东西。

  1. 角色分配名称必须是唯一的。一旦创建了分配,您就无法更改它,因此您不能使用相同的 guid,否则看起来您正在尝试更新不允许的角色分配。

  2. 您不能使用 powershell 数组作为输入参数。使用 az cli,有效的数组参数如下所示:

    az deployment group create `
      --resource-group $RESOURCE_GROUP `
      --template-file "./rbac-role.json" `
      --parameters `
      principalId=$objectid `
      builtInRoleType="['StorageQueueDataContributor', 'StorageTableDataContributor']" `
      roleNameGuid="['974c5e8b-45b9-4653-ba55-5f855dd0fb88', '0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3']"     
    

要消除生成唯一角色名称的需要,您可以使用 guid() function:

Creates a value in the format of a globally unique identifier based on the values provided as parameters.

因此这将生成一个唯一的字符串,但您可以多次 运行 同一个模板,它始终是相同的唯一字符串:

"name": "[guid(subscription().subscriptionId, resourceGroup().name, parameters('builtInRoleType')[0]], parameters('principalId'))]",

如果你想同时创建多个作业,你可以使用 copy() function:

{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "principalId": {
      "type": "string"
    },
    "builtInRoleType": {
      "type": "array",
      "allowedValues":[
        "Owner",
        "Contributor",
        "Reader",
        "StorageQueueDataContributor",
        "StorageTableDataContributor"
      ]
    }
  },
  "variables": {
    "Owner": "8e3af657-a8ff-443c-a75c-2fe8c4bcb635",
    "Contributor": "'b24988ac-6180-42a0-ab88-20f7382dd24c",
    "Reader": "acdd72a7-3385-48ef-bd42-f606fba81ae7",
    "StorageQueueDataContributor": "974c5e8b-45b9-4653-ba55-5f855dd0fb88",
    "StorageTableDataContributor": "0a9a7e1f-b9d0-4cc4-a60d-0319b160aaa3"
  },
  "resources": [
    {
      "copy": {
        "name": "roleAssignment",
        "count": "[length(parameters('builtInRoleType'))]"
      },
      "type": "Microsoft.Authorization/roleAssignments",
      "apiVersion": "2020-04-01-preview",
      "name": "[guid(subscription().subscriptionId, resourceGroup().name, parameters('builtInRoleType')[copyIndex()], parameters('principalId'))]",
      "properties": {
        "roleDefinitionId": "[subscriptionResourceId('Microsoft.Authorization/roleAssignments', variables(parameters('builtInRoleType')[copyIndex()]))]",
        "principalId": "[parameters('principalId')]"
      }
    }
  ]
}

那么您就可以像这样调用模板了:

az deployment group create `
  --resource-group $RESOURCE_GROUP `
  --template-file "./rbac-role.json" `
  --parameters `
  principalId=$objectid `
  builtInRoleType="['StorageQueueDataContributor', 'StorageTableDataContributor']"