向服务主体授予对 Azure 的访问权限

已完成

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

注意

本单元中显示的命令用于说明概念。 请暂时不要运行这些命令。 稍后你将练习在此处学到的知识。

服务主体授权

到目前为止,你重点学习了什么是服务主体,以及如何使用它们向 Microsoft Entra ID 证明管道的标识。 这一切都与身份验证有关。

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

备注

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

为管道选择正确的角色分配

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

被分派人

使用服务主体时,需要为该服务主体分配角色。 可以使用服务主体的应用程序 ID 来标识该被分派人的正确服务主体。

角色

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

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

注意

应仅向服务主体授予执行其作业所需的最低权限。 大多数情况下,所有者角色对于部署管道来说过于宽松。

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

注意

自定义角色定义是为 Azure 资源授予权限的一种强大方法,但可能难以使用。 精确确定需要将哪些权限添加到自定义角色定义并非总是很容易,而且可能会无意中使角色定义过于严格或过于宽松。 如果不确定该怎么做,最好改为使用内置角色定义。 自定义角色定义不在本模块的讨论范围内。

范围

你需要确定分配角色的大致范围。 此决定会影响服务主体可修改的资源数。 常见范围包括:

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

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

选择合适的角色分配

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

  • 尽可能使用最严格的角色。 如果你的管道只打算部署基本 Bicep 模板而不管理角色分配,请不要使用所有者角色。
  • 尽可能使用最窄的范围。 大多数管道只需要将资源部署到资源组,因此不应为它们提供订阅范围的角色分配。
  • 对于许多管道,角色分配的一个好的默认选项是资源组范围上的参与者角色。
  • 请考虑你的管道执行的所有操作,还有它将来可能会执行的各项操作。 例如,你可能考虑为网站的部署管道创建自定义角色定义,并且仅授予应用服务和 Application Insights 的权限。 下个月,你可能需要将 Azure Cosmos DB 帐户添加到 Bicep 文件,但自定义角色阻止创建 Azure Cosmos DB 资源。 相反,通常最好使用内置角色或内置角色的组合,以避免重复更改你的角色定义。 请考虑使用 Azure Policy 对允许的服务、SKU 和位置强制实施治理要求。
  • 测试管道来验证角色分配是否有效。

混搭并匹配角色分配

你可创建多个角色分配,在不同的范围提供不同的权限。 例如,你可将整个订阅范围的读取者角色分配给服务主体,然后将特定资源组的参与者角色单独分配给该服务主体。 当服务主体尝试使用资源组时,将应用更宽松的分配。

使用多个环境

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

你应为每个环境创建单独的服务主体,并为每个服务主体授予其部署所需的最小权限集。 请特别注意,不要将生产部署的权限与用于部署到非生产环境的权限相混合。

为服务主体创建角色分配

若要为服务主体创建角色分配,请使用 az role assignment create 命令。 你需要指定被分派人、角色和范围:

az role assignment create \
  --assignee b585b740-942d-44e9-9126-f1181c95d497 \
  --role Contributor \
  --scope "/subscriptions/f0750bbe-ea75-4ae5-b24d-a92ca601da2c/resourceGroups/ToyWebsite" \
  --description "The deployment pipeline 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 b585b740-942d-44e9-9126-f1181c95d497 `
  -RoleDefinitionName Contributor `
  -Scope '/subscriptions/f0750bbe-ea75-4ae5-b24d-a92ca601da2c/resourceGroups/ToyWebsite' `
  -Description "The deployment pipeline for the company's website needs to be able to create resources within the resource group."

让我们看看每个参数:

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

提示

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

备注

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

使用一个操作创建服务主体和角色分配

你还可在创建服务主体的同时创建角色分配。 代码类似于你在前述单元中用于创建服务主体的命令,但是有一些其他参数:

az ad sp create-for-rbac \
  --name MyPipeline \
  --role Contributor \
  --scopes "/subscriptions/f0750bbe-ea75-4ae5-b24d-a92ca601da2c/resourceGroups/ToyWebsite"
$servicePrincipal = New-AzADServicePrincipal `
  -DisplayName MyPipeline `
  -Role Contributor `
  -Scope '/subscriptions/f0750bbe-ea75-4ae5-b24d-a92ca601da2c/resourceGroups/ToyWebsite'

使用 Bicep 授予访问权限

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

resource roleAssignment 'Microsoft.Authorization/roleAssignments@2023-04-01-preview' = {
  name: guid(principalId, roleDefinitionId, resourceGroup().id)
  properties: {
    principalType: 'ServicePrincipal'
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleDefinitionId)
    principalId: principalId
    description: 'The deployment pipeline 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/f0750bbe-ea75-4ae5-b24d-a92ca601da2c/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c)来表示。
  • principalId 是服务主体的对象 ID。 请确保不使用应用程序 ID 或应用程序注册的对象 ID。
  • description 是角色分配的用户可读说明。