如何使用 ARM 模板为 App Registration Service Principal 部署 roleAssignment?

How to use ARM templates to deploy a roleAssignment for an App Registration Service Principal?

在我当前的项目中,我正在使用 Azure AD 中预先创建的应用程序注册服务主体。我正在使用 ARM 模板创建一个 StorageV2 帐户和一些 blob 容器,然后创建一个 roleAssignment,将 Storage Blob Contributor 权限授予其中一个服务主体。 ARM 模板的相关部分在本 post.

的末尾

我发现,如果我将常规 AD 用户(例如我自己或我的同事)的 ObjectId 设置为 PrincipalId,脚本将正确运行。但是,我无法让它与服务主体一起工作。

如果我使用服务主体的 ObjectId,则会出现以下错误:

Deployment failed. Correlation ID: 40e0c146-165a-47c0-b022-ac04781d8194. {
  "error": {
    "code": "PrincipalTypeNotSupported",
    "message": "Principals of type Application cannot validly be used in role assignments."
  }
}

我发现了一些针对 Azure Powershell 用户的建议,我应该改用应用程序(客户端)ID,我试过了,但收到以下错误(Guids 已编辑):

Deployment failed. Correlation ID: 5c725a51-230a-4d85-bb61-b2f4cdf849ff. {
  "error": {
    "code": "PrincipalNotFound",
    "message": "Principal 9f****30 does not exist in the directory db****75."
  }
}

所以ObjectId能找到但不能用,ClientId找不到。

我发现如果我使用 Azure Powershell 并使用 New-AzureRmRoleAssignment 命令,我可以通过向 -ObjectId 提供服务主体的 ObjectId 来重现 PrincipalTypeNotSupported 错误] 转变。但是,该命令也有一个 -ServicePrincipalName 开关作为替代,如果我给服务主体的 ClientId,它就可以工作!

ARM 模板是否有任何等效于 -ServicePrincipalName 的东西?如果没有,是否有其他方法可以实现此目的?我可以使用 Azure Powershell 作为解决方法,但它比我想要的更混乱。

如果这是一个功能差距,哪里是报告它的最佳地点?

ARM模板相关部分如下:

"resources": [
    {
        "name": "[variables('storageAccountName')]",
        "type": "Microsoft.Storage/storageAccounts",
        "location": "[resourceGroup().location]",
        "apiVersion": "2018-07-01",
        "sku": {
            "name": "[parameters('storageAccountSku')]"
        },
        "dependsOn": [],
        "tags": {
            "displayName": "Storage Account"
        },
        "kind": "StorageV2",
        "properties": {
            "accessTier": "Hot",
            "supportsHttpsTrafficOnly": true,
            "networkAcls": {
                "bypass": "AzureServices",
                "virtualNetworkRules": [],
                "ipRules": [],
                "defaultAction": "Deny"
            }
        },
        "resources": [
            {
                "type": "blobServices/containers",
                "name": "[concat('default/', variables('myBlobContainerName'))]",
                "apiVersion": "2018-07-01",
                "dependsOn": [
                    "[variables('storageAccountName')]"
                ],
                "resources": [
                    {
                        "type": "Microsoft.Authorization/roleAssignments",
                        "name": "[variables('myRoleAssignmentGuid')]",
                        "apiVersion": "2018-07-01",
                        "properties": {
                            "roleDefinitionId": "[concat('/subscriptions/', subscription().subscriptionId, '/providers/Microsoft.Authorization/roleDefinitions/ba92f5b4-2d11-453d-a403-e96b0029c9fe')]",
                            "principalId": "[variables('myPrincipalId')]"
                        },
                        "dependsOn": [
                            "[concat('Microsoft.Storage/storageAccounts/', variables('storageAccountName'), '/blobServices/default/containers/', variables('myBlobContainerName'))]"
                        ]
                    }
                ]
            }
        ]
    }
]

终于解决了这个问题,部分感谢@4c74356b41 的指点。

创建应用程序注册对象时,还会在企业应用程序下创建同名对象。它有相同的 ApplicationId,但有不同的 ObjectId,它是我们的 ARM 脚本需要的这个企业应用程序对象的 ObjectId

您可以在门户中找到此对象,方法是转到“应用程序注册”条目,然后单击 Managed application in...

之后的 link

Screenshot of App Registration with Link

在相应的企业应用程序对象上后,您可以从属性中获取 ObjectId,并在 ARM 模板中使用此值 principalId

在撰写本文时,Microsoft 文档对此有点含糊,术语应用程序和服务主体似乎超载了。 This article 表示,当您注册应用程序时,您会获得一个应用程序对象和一个服务主体对象,但不会一次使用短语企业应用程序,或参考应用程序注册 objects本身,所以不清楚哪个是哪个。

我假设应用程序 == 应用程序注册和服务主体 == 企业应用程序。 和上面的解决方案一样,似乎表明是这种情况。