向服务主体授予对 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 00001111-aaaa-2222-bbbb-3333cccc4444 \
--role Contributor \
--scope "/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/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 00001111-aaaa-2222-bbbb-3333cccc4444 `
-RoleDefinitionName Contributor `
-Scope '/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/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。 例如,参与者角色具有角色定义 IDb24988ac-6180-42a0-ab88-20f7382dd24c
。 在 Bicep 文件中指定它时,可使用完全限定的资源 ID(例如/subscriptions/aaaa0a0a-bb1b-cc2c-dd3d-eeeeee4e4e4e/providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c
)来表示。principalId
是服务主体的对象 ID。 请确保不使用应用程序 ID 或应用程序注册的对象 ID。description
是角色分配的用户可读说明。