向工作负载标识授予对 Azure 的访问权限

已完成

工作负荷标识本身无法在 Azure 环境中执行任何操作,就像用户无法处理你的 Azure 资源一样,除非它们得到授权。 在本单元中,你将了解如何授权工作负荷标识部署和配置 Azure 资源,同时避免授予不必要的权限。

工作负载标识授权

到目前为止,你重点学习了什么是工作负载标识,以及如何使用它们向 Microsoft Entra ID 证明部署工作流的标识。 这一切都与身份验证有关。

在 Microsoft Entra ID 对工作负载标识进行身份验证后,下一个问题将是:此工作负载标识可以做什么? 这是“授权”的概念。 这是 Azure 基于角色的访问控制 (RBAC) 系统的职责,有时也称为标识和访问管理 (IAM)。 使用 Azure RBAC,可向工作负载标识授予访问特定资源组、订阅或管理组的权限。

注意

这里执行的一切操作都是使用 Azure RBAC 系统授予访问权限来创建和管理 Azure 资源,例如存储帐户、Azure 应用服务计划和虚拟网络。 Microsoft Entra ID 也有自己的角色系统,有时称为目录角色。 可使用这些角色向工作负载标识授予管理 Microsoft Entra ID 的权限。 本模块不会深入讨论此主题,但请注意在某些文档中,术语“角色”用于这两种情况

为工作流选择正确的角色分配

角色分配有三个关键部分:将角色分配给谁(被分派人)、他们可执行什么操作(角色),以及角色分配应用于哪些资源(范围)

被分派人

使用工作负载标识时,将为其分配角色。 若要分配角色,需要首先创建服务主体,这样就可以在 Azure 中授予应用程序角色。 创建服务主体后,可以继续使用应用程序注册的应用程序 ID。

若要创建服务主体,请使用 az ad sp create 命令并指定应用程序注册的应用 ID:

az ad sp create --id A123b4567c-1234-1a2b-2b1a-1234abc12345

若要创建服务主体,请使用 New-AzADServicePrincipal cmdlet 并指定应用程序注册的应用 ID:

New-AzADServicePrincipal -AppId A123b4567c-1234-1a2b-2b1a-1234abc12345

角色

若要确定要分配的角色,可能还有一些操作。 在 Azure 中,有几个常见角色:

  • 读者:允许被分派人读取资源信息,但禁止修改或删除这些资源。
  • 参与者:允许被分派人创建资源,还允许他们读取和修改现有资源。 但是,参与者无法向其他主体授予对资源的访问权限。
  • 所有者:允许完全控制资源,包括向其他主体授予访问权限。

注意

仅向工作负载标识授予执行其作业所需的最低权限。 大多数情况下,所有者角色对于部署工作流来说过于宽松。

还有许多特定角色提供对部分功能的访问权限。 你甚至可创建自己的自定义角色定义,来指定要分配的权限的确切列表。

备注

自定义角色定义是为 Azure 资源授予权限的一种强大方法,但可能难以使用。 精确确定需要将哪些权限添加到自定义角色定义并非总是很容易, 而且可能会无意中使角色定义过于严格或过于宽松。

如果不确定该怎么做,最好使用内置角色定义之一。 自定义角色定义不在本模块的讨论范围内。

范围

你需要确定分配角色的大致范围。 此决定会影响工作负载标识可修改的资源数。 常见范围包括:

  • 单个资源:可以授予对特定资源的访问权限。 通常,部署工作流不使用此范围,因为工作流会创建尚不存在的资源,或者重新配置多个资源。
  • 资源组:可以授予对资源组中所有资源的访问权限。 参与者和所有者还可在组中创建资源。 对于许多部署工作流来说,这是一个不错的选择。
  • 订阅:可以授予对订阅中所有资源的访问权限。 如果单个订阅中有多个应用程序、工作负载或环境,则可向订阅的范围授予权限。 但对于部署工作流来说,这通常太宽松了。 应改为考虑将角色分配范围限定为资源组,除非部署工作流需要创建资源组。

请记住,角色分配会被继承。 如果在订阅中分配角色,则被分派人有权访问该订阅中的每个资源组和资源。

选择合适的角色分配

现在你已了解角色分配的组成部分,接下来可为你的方案确定适当的值。 下面是需要考虑的一些常规指导:

  • 尽可能使用最严格的角色。 如果你的工作流只打算部署基本 Bicep 文件而不管理角色分配,请不要使用所有者角色。

  • 尽可能使用最窄的范围。 大多数工作流只需要将资源部署到资源组,因此不应为它们提供订阅范围的角色分配。

  • 对于许多工作流,角色分配的一个好的默认选项是资源组范围上的参与者角色。

  • 请考虑你的工作流执行的所有操作,还有它将来可能会执行的各项操作。 例如,你可能考虑为网站的部署工作流创建自定义角色定义,并且仅授予应用服务和 Application Insights 的权限。 下个月,你可能需要将 Azure Cosmos DB 帐户添加到 Bicep 文件,但自定义角色阻止创建 Azure Cosmos DB 资源。

    相反,通常最好使用内置角色或内置角色的组合,以避免重复更改你的角色定义。 请考虑使用 Azure Policy 对允许的服务、SKU 和位置强制实施治理要求。

  • 测试工作流来验证角色分配是否有效。

混搭并匹配角色分配

你可创建多个角色分配,在不同的范围提供不同的权限。 例如,可以将工作负载标识分配给具有整个订阅范围的读者角色。 可以将特定资源组的参与者角色单独分配给同一工作负荷标识。 当工作负载标识尝试使用资源组时,将应用更宽松的分配。

使用多个环境

你可能会使用多个环境,例如应用程序的开发、测试和生产环境。 每个环境的资源应部署到不同的资源组或订阅。

应为每个环境创建单独的工作负载标识。 为每个工作负载标识授予其部署所需的最小权限集。 请特别注意,不要将生产部署的权限与用于部署到非生产环境的权限相混合。

为工作负载标识创建角色分配

若要为工作负载标识创建角色分配,请使用 az role assignment create 命令。 你需要指定被分派人、角色和范围:

az role assignment create \
  --assignee A123b4567c-1234-1a2b-2b1a-1234abc12345 \
  --role Contributor \
  --scope "/subscriptions/B123a4567c-1234-2b1a-1b2b-11a2b01b2b3c0/resourceGroups/ToyWebsite" \
  --description "The deployment workflow for the company's website needs to be able to create resources within the resource group."

让我们看看每个参数:

  • --assignee 指定工作负载标识。 可以通过多种方式指定此功能,但最好使用应用程序 ID,因为它可以避免产生歧义。
  • --role 指定角色。 如果使用内置角色,则可按名称指定它。 如果使用自定义角色定义,请指定完整的角色定义 ID。
  • --scope 指定范围。 这通常是单个资源、资源组或订阅的资源 ID。
  • --description 是角色分配的用户可读说明。

若要为工作负载标识创建角色分配,请使用 New-AzRoleAssignment cmdlet。 指定被分派人、角色和范围:

New-AzRoleAssignment `
  -ApplicationId A123b4567c-1234-1a2b-2b1a-1234abc12345 `
  -RoleDefinitionName Contributor `
  -Scope '/subscriptions/B123a4567c-1234-2b1a-1b2b-11a2b01b2b3c0/resourceGroups/ToyWebsite' `
  -Description "The deployment workflow for the company's website needs to be able to create resources within the resource group."

让我们看看每个参数:

  • -ApplicationId 指定工作负载标识的应用程序注册 ID。
  • -RoleDefinitionName 指定内置角色的名称。 如果使用自定义角色定义,请改为使用 -RoleDefinitionId 参数指定完整的角色定义 ID。
  • -Scope 指定范围。 这通常是单个资源、资源组或订阅的资源 ID。
  • -Description 是角色分配的用户可读说明。

提示

最好是通过指定说明为角色分配提供理由。 说明可帮助稍后查看角色分配的任何人理解其用途,并了解你如何决定被分派人、角色和范围。

备注

角色分配可能需要几分钟才能生效。

通过使用 Bicep 授予访问权限

角色分配是 Azure 资源。 这意味着可使用 Bicep 创建角色分配。 如果通过使用 Bicep 初始化资源组,然后通过使用工作负荷标识将资源部署到资源组,则可执行此操作。 下面是上述角色分配的示例 Bicep 定义:

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(principalId, roleDefinitionId, resourceGroup().id)
  properties: {
    principalType: 'ServicePrincipal'
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId)
    principalId: principalId
    description: 'The deployment workflow for the company\'s website needs to be able to create resources within the resource group.'
  }
}

让我们看看每个参数:

  • name 是角色分配的全局唯一标识符 (GUID)。 最好使用 Bicep 中的 guid() 函数来创建 GUID。 要确保为每个角色分配创建唯一名称,请使用主体 ID、角色定义 ID 和范围作为函数的种子参数。

  • principalType 应设置为 ServicePrincipal

  • roleDefinitionId 是要分配的角色定义的完全限定的资源 ID。 大多数情况下,你可使用内置角色,因此可在 Azure 内置角色文档中找到角色定义 ID。

    例如,参与者角色具有角色定义 ID b24988ac-6180-42a0-ab88-20f7382dd24c。 在 Bicep 文件中指定它时,可使用完全限定的资源 ID,例如 /subscriptions/B123a4567c-1234-2b1a-1b2b-11a2b01b2b3c0/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c

  • principalId 是服务主体的对象 ID。 请确保不使用应用程序 ID 或应用程序注册的对象 ID。

  • description 是角色分配的用户可读说明。