使用 CI/CD 时 Azure 中的端到端治理

为组织开发治理模型时,请务必记住,Azure 资源管理器 只是管理资源的一种方式。 如果未正确保护,Azure DevOps 和持续集成和持续交付(CI/CD)自动化可能是意外的安全后门。 应通过镜像用于 Resource Manager 的基于角色的访问控制 (RBAC) 模型来保护这些资源。

端到端治理的概念与供应商无关。 此处所述的实现使用 Azure DevOps,但还简要介绍了替代方法。

潜在的用例

此参考实现和演示是开源的,旨在用作 DevOps 新手且需要创建用于部署到 Azure 的治理模型的组织的教学工具。 请仔细阅读此方案,了解此示例存储库中使用的模型背后的决策。

任何治理模型都必须绑定到组织的业务规则,这些规则反映在访问控制的任何技术实现中。 本示例模型使用了一个虚构的公司,有以下常见场景(有业务需求):

  • 与业务领域和权限模型一致的 Microsoft Entra 组
    该组织有许多垂直业务领域,如“水果”和“蔬菜”,主要独立运营。 在每个业务域中,有两个不同的权限级别,这些级别被映射到不同的 *-admins*-devs Microsoft Entra 组。 这允许开发人员在云中配置权限时成为目标。

  • 部署环境
    每个团队都有两个环境:

    • 生产。 只有管理员具有提升的权限。
    • 非生产性 所有开发人员都有提升的权限(鼓励试验和创新)。
  • 自动化目标
    每个应用程序都应实现 Azure DevOps,而不仅仅是持续集成(CI),还应实现持续部署(CD)。 例如,可以通过对 Git 存储库的更改自动触发部署。

  • 到目前为止的云旅程
    组织以孤立的项目模型开始,以加速向云迁移的过程。 但现在,他们正在探索打破孤岛和鼓励协作的选项,通过创建“协作”和“超市”项目。

此简化关系图显示了 Git 存储库中的分支如何映射到开发、过渡和生产环境:

映射到各种 Web 环境的 Git 存储库分支的简化关系图
下载此关系图的 SVG

建筑

此图显示了如何从 Resource Manager 和 CI/CD 链接到 Microsoft Entra ID 是建立端到端治理模型的关键。

以 Microsoft Entra ID 为中心的端到端治理概述
下载此体系结构的 SVG 图

注意

为了使概念更易于理解,该图只说明了 “蔬菜” 域。 “水果”域看起来类似,并且使用相同的命名约定。

工作流

编号反映了 IT 管理员和企业架构师考虑和配置其云资源的顺序。

  1. Microsoft Entra ID

    我们将 Azure DevOps 与 Microsoft Entra ID 集成,以便提供统一的标识平台。 这意味着开发人员对 Azure DevOps 和 Resource Manager 使用相同的 Microsoft Entra 帐户。 不会单独添加用户。 相反,成员身份是通过 Microsoft Entra 组分配的,这样我们就可以通过删除他们在 Microsoft Entra 组中的成员身份,一步去除开发人员对资源的访问权限。 对于每个域,我们将创建:

    • Microsoft Entra 组。 每个域有两个组(本文后面的步骤 4 和步骤 5 中进一步介绍)。
    • 服务主体。 在每个环境中,设置一个显式服务主体
  2. 生产环境

    为了简化部署,此参考实现使用资源组来表示生产环境。 实际上,应使用其他订阅

    对此环境的特权访问仅限于管理员。

  3. 开发环境

    为了简化部署,此参考实现使用资源组来表示开发环境。 实际上,应使用其他订阅

  4. 资源管理器中的角色分配

    尽管我们的 Microsoft Entra 组名称表示角色,但在配置角色分配之前,不会应用访问控制。 这会将角色分配给特定范围的 Microsoft Entra 主体。 例如,开发人员在生产环境中拥有“参与者”角色。

    Microsoft Entra 主体 开发环境 (资源管理器) 生产环境 (资源管理器)
    veggies-devs-group 所有者 读取者
    veggies-admins-group 所有者 所有者
    veggies-ci-dev-sp 自定义角色 *
    veggies-ci-prod-sp 自定义角色 *

    * 为了简化部署,此参考实现将 Owner 角色分配给服务主体。 但是,在生产环境中,应创建一个自定义角色,以防止服务主体删除已经放置在资源上的任何管理锁。 这有助于防止资源意外损坏,例如数据库删除。

    若要了解各个角色分配背后的原因,请参阅本文后面的 注意事项部分

  5. Azure DevOps 中的安全组分配

    安全组功能类似于 Resource Manager 中的角色。 利用内置角色,并且开发人员的角色默认为参与者。 管理员将分配到 项目管理员 安全组以获取提升的权限,从而允许他们配置安全权限。

    请注意,Azure DevOps 和资源管理器具有不同的权限模型:

    因此,-admins-devs 组的成员身份必须相互排斥。 否则,受影响的人员在 Azure DevOps 中的访问权限将低于预期。

    组名称 资源管理器角色 Azure DevOps 角色
    fruits-all
    fruits-devs 参与者 参与者
    fruits-admins 所有者 项目管理员
    veggies-all
    veggies-devs 参与者 参与者
    veggies-admins 所有者 项目管理员
    infra-all
    infra-devs 参与者 参与者
    infra-admins 所有者 项目管理员

    在有限协作场景中,例如水果团队邀请蔬菜团队在单个存储库上进行协作,他们将使用 veggies-all 组。

    若要了解各个角色分配背后的原因,请参阅本文后面的 注意事项部分

  6. 服务连接

    在 Azure DevOps 中,服务连接是一个围绕凭据的泛型包装器。 我们创建一个服务连接,用于保存服务主体客户端 ID 和客户端密码。 项目管理员可以根据需要配置对此 受保护资源的访问权限,例如在部署前需要人工审批时。 此参考体系结构在服务连接上具有两项最低保护:

    • 管理员必须配置 管道权限 来控制哪些管道可以访问凭据。
    • 管理员还必须配置分支控件检查,以便只有在 production 分支的上下文中运行的管道才能使用 prod-connection
  7. Git 存储库

    由于我们的服务连接通过 分支控制连接到分支,因此配置 Git 存储库的权限并应用 分支策略至关重要。 除了要求传递 CI 生成之外,我们还要求拉取请求至少有两个审批者。

组件

替代方案

端到端治理的概念与供应商无关。 虽然本文重点介绍 Azure DevOps,但 Azure DevOps Server 可用作本地替代项。 或者,也可以使用一组技术,使用 JenkinsGitLab 等选项来实现开源的 CI/CD 开发管道。

Azure Repos 和 GitHub 都是使用开源 Git 版本控制系统构建的平台。 虽然其功能集有些不同,但两者都可以集成到 CI/CD 的全局治理模型中。 GitLab 是另一个基于 Git 的平台,可提供可靠的 CI/CD 功能。

此方案使用 Terraform 作为其基础结构即代码 (IaC) 工具。 替代项包括 Jenkins、AnsibleChef

注意事项

若要在 Azure 中实现端到端治理,请务必了解从开发人员的计算机到生产的路径的安全性和权限配置文件。 下图演示了 Azure DevOps 的基线 CI/CD 工作流。 红色锁图标 指示用户必须配置的安全权限。 未配置或配置权限不当会使工作负荷易受攻击。

使用 Azure DevOps 演示基线 CI/CD 工作流的 关系图
下载此工作流的 SVG

若要成功保护工作负荷,必须在工作流中使用安全权限配置和人工检查的组合。 任何 RBAC 模型还必须扩展到管道和代码,这一点很重要。 这些应用通常使用特权标识运行,如果指示这样做,则会销毁工作负荷。 若要防止这种情况发生,应在存储库上配置 分支策略,以要求人工批准,然后再接受触发自动化管道的更改。

部署阶段 责任 描述
拉取请求 用户 工程师应该对他们的工作进行同级评审,包括管道代码本身。
分支保护 共享 配置 Azure DevOps 以拒绝不符合某些标准的更改,如 CI 检查和同级评审(通过拉取请求)。
管道即代码 用户 如果管道代码指示这样做,构建服务器将删除整个生产环境。 通过组合使用拉取请求和分支保护规则(如人工批准),有助于防止发生这种情况。
服务连接 共享 配置 Azure DevOps 以限制对这些凭据的访问。
Azure 资源 共享 在资源管理器中配置 RBAC。

在设计治理模型时,必须考虑以下概念和问题。 请记住此示例组织的可能的用例

1.使用分支策略保护环境

由于源代码定义和触发部署,因此第一道防线是保护源代码管理(SCM)存储库。 在实践中,这是通过使用 拉取请求工作流分支策略来实现的,这些策略定义可接受代码前的检查和要求。

规划端到端治理模型时,特权用户(veggies-admins)将负责配置分支保护。 用于保护部署的常见分支保护检查包括:

  • 要求传递 CI 生成。 对建立基线代码质量很有帮助,例如代码 Lint 分析、单元测试,甚至是安全检查(如病毒和凭据扫描)。

  • 要求同级评审 再由他人核实,以确保代码按预期工作。 对管道代码进行更改时,请格外小心。 与 CI 生成相结合,使同级评审不那么乏味。

如果开发人员尝试直接推送到生产环境,会发生什么情况?

请记住,Git 是分布式 SCM 系统。 开发人员可以选择直接提交到本地 production 分支。 但是,正确配置 Git 时,Git 服务器会自动拒绝此类推送。 例如:

remote: Resolving deltas: 100% (3/3), completed with 3 local objects.
remote: error: GH006: Protected branch update failed for refs/heads/main.
remote: error: Required status check "continuous-integration" is expected.
To https://github.com/Azure/devops-governance
 ! [remote rejected] main -> main (protected branch hook declined)
error: failed to push some refs to 'https://github.com/Azure/devops-governance'

请注意,示例中的工作流与供应商无关。 拉取请求和分支保护功能可以从多个 SCM 提供程序那里获得,包括 Azure ReposGitHubGitLab

将代码接受到受保护的分支后,生成服务器将应用下一层访问控制(例如 Azure Pipelines)。

2.安全主体需要哪些访问权限?

在 Azure 中,安全主体 可以是 用户主体,也可以是 无外设主体,例如服务主体或托管标识。 在所有环境中,安全主体应遵循 最低特权原则。 虽然安全主体在预生产环境中可能拥有扩展的访问权限,但生产 Azure 环境应尽量减少静态权限,支持按需(JIT)访问和 Microsoft Entra 条件访问。 为用户主体创建 Azure RBAC 角色分配,使其与这些最低特权主体保持一致。

与 Azure DevOps RBAC 不同,对 Azure RBAC 进行建模也很重要。 管道的目的是最大程度地减少对 Azure 的直接访问。 除了创新、学习和问题解决等特殊情况外,大多数与 Azure 的交互都应通过专用管道和封闭管道进行。

对于 Azure Pipeline 服务主体,建议使用自定义角色 来阻止其删除资源锁,以及执行超出其目的范围的其他破坏性操作。

3. 为用于访问生产环境的服务主体创建自定义角色

为 CI/CD 生成代理提供所有者角色和权限是一个常见错误。 如果管道还需要执行标识角色分配或其他特权操作(如 Key Vault 策略管理),则参与者权限是不够的。

但是,如果被告知要这样做,CI/CD 生成代理将删除整个生产环境。 为了避免发生不可逆的破坏性更改,我们创建了一个自定义角色,它可以:

  • 删除 Key Vault 访问策略
  • 删除管理锁,根据设计,这些锁应该防止资源被删除(在受管制的行业中,这是一个常见的要求)

为此,我们将创建自定义角色并删除 Microsoft.Authorization/*/Delete 操作。

{
  "Name": "Headless Owner",
  "Description": "Can manage infrastructure.",
  "actions": [
    "*"
  ],
  "notActions": [
    "Microsoft.Authorization/*/Delete"
  ],
  "AssignableScopes": [
    "/subscriptions/{subscriptionId1}",
    "/subscriptions/{subscriptionId2}",
    "/providers/Microsoft.Management/managementGroups/{groupId1}"
  ]
}

如果为此删除了过多的权限,请参阅 Azure 资源提供程序操作的官方文档中的完整列表,并根据需要调整角色定义。

部署此方案

该场景超出了 Resource Manager 的范围。 这就是我们使用 Terraform 的原因,它使我们还可以在 Microsoft Entra ID 中创建主体,并通过单一的基础结构即代码工具启动 Azure DevOps。

有关源代码和详细说明,请访问 GitHub 存储库 Azure 演示中的治理 - 从 DevOps 到 ARM

定价

Azure DevOps 成本取决于组织中需要访问权限的用户数和其他因素,例如,所需的并发生成/发布数,以及用户数。 Azure Repos 和 Azure Pipelines 是 Azure DevOps 服务的功能。 有关详细信息,请参阅 Azure DevOps 定价

在 Microsoft Entra ID 中,高级 P1 和高级 P2 版本中提供了此方案所需的组访问管理类型。 这些级别的定价是按每个用户计算的。 有关详细信息,请参阅 Microsoft Entra 定价

贡献者

本文由Microsoft维护。 它最初由以下参与者编写。

主要作者

后续步骤