亚马逊AWS官方博客
借助 Cloud Foundations 产品工厂规划设计并一键部署云上多账户访问控制及权限策略等基础设施资源
Cloud Foundations 的设计和实现围绕云底座理念的六大类三十项能力建设展开。之前聚焦的能力建设主要集中在安全、基础设施、治理和风险管理等云基建方面,以基础着陆区为中心构建符合最佳实践和安全规范的多账户云上运行环境。当基础着陆区搭建好以后,工作负载隔离能力建设是最重要的后续工作之一,也是企业上云旅途可持续发展不可或缺的一环。该能力旨在创建和管理工作负载的隔离环境以减少缺陷和威胁所造成的的影响。其中的一个能力点是提供预批准可部署的架构。该能力点的核心是通过预批准的模式库提供常见和可重复的机制以维护工作负载周围的控件和边界。简而言之,该能力需要支持“定义、批准、部署”服务工作负载的架构。
架构可大可小,例如一个由自动扩缩组管理实例的弹性堡垒机架构[1]。事实上跳出“架构”的传统思维,我们可以把任何有意义的资源组合视为合理架构。回归到云上环境构建话题,在基础着陆区构建完毕之后,一般至少还要做两项架构建设:云上网络联通和访问权限控制。基础着陆区部署与这两项架构建设最大的区别在于标准化与定制化的不同。基础着陆区对每个客户而言大同小异,而网络和权限对每个客户而言可谓“大异小同”。
云上网络联通架构主要通过 Cloud Foundations 的共享网络、网关联通[2],网络流量检查[3]和多阶段流水线[4]等功能支持构建,可以满足大部分复杂网络架构建设需求。而访问权限控制主要涉及多个成员账户内 Amazon IAM 相关用户、角色和策略以及安全账户内 Amazon IAM Identity Center (身份中心)的权限集、目录组等资源的设计与部署。关于访问控制还有一个重要事项为外部身份供应商与身份中心的集成,该话题本文暂不涉及。
每个客户需要创建和管理的访问权限资源千差万别,为此 Cloud Foundations 近期新增“产品工厂”功能满足定制化的云上资源自动化创建和管理需求。在此我们可以把一套架构具体地视为一个“产品”。通过 JSON 格式定义产品,通过 Amazon Service Catalog 预置产品生成流水线管道,执行并批准流水线从而部署该产品至指定账户和区域。例如可以为某项目设计定义一套访问权限控制标准,制定预批准的目录组、权限集、相关客户策略、角色等。还可以此为模版,为其他项目建立类似访问权限控制资源,从而达到最小权限和精细化管理要求。
产品工厂设计思想
产品工厂的设计思想可以简单归纳为“基础设施即定义” (Infrastructure as Definition, IaD)。这是在目前比较流行的基础设施即代码(Infrastructure as Code, IaC)基础上的简化和升级。基础设施即代码需要撰写代码,编译执行代码从而管理云资源。常见基础设施即代码语言包括 Terraform,基于 AWS 云开发包(CDK)或 Pulumi 的其他高级编程语言等。而基础设施即定义不需要您掌握编程语言,只需要了解 JSON 语法即可。此外二者还有以下主要区别:
项目 | 基础设施即代码 IaC | 基础设施即定义 IaD |
编写语言 | Terraform,基于 AWS 云开发包(CDK)或 Pulumi 的其他高级编程语言等 | JSON |
代码存储 | 自行准备,例如 Amazon CodeCommit, GitHub, GitLab 等 | Amazon AppConfig(可改造使用 GitLab 等) |
编译运行时环境 | 根据编写语言要求自行准备相应实例硬件和软件环境 | Cloud Foundations 通过 Amazon CodeBuild 负责解释运行产品定义 |
持续集成和部署 | 自行准备,例如 Amazon CodePipeline, GitHub Actions, GitLab CI/CD 等 | Cloud Foundations 通过 Amazon CodePipeline 负责持续集成和部署过程 |
产品目录和管理 | 自行准备 | Cloud Foundations 通过 Amazon Service Catalog 负责产品目录管理和运维 |
从上表对比来看,基于 Cloud Foundations 的基础设施即定义在诸多方面简化优化了云资源自动化创建和标准化管理过程。诚如其名所言,只要把产品“定义”好,其他的事情就可以交由 Cloud Foundations 负责。如此您可以更加专注于产品或架构设计本身,切实减轻除此之外的繁杂后勤事务,进一步提高工作效率和设计质量。
产品定义基本结构
运用“分而治之”思想我们对产品进行拆解。一个产品或架构无论多复杂都可以拆解到最小单元,即在何账户何区域部署何服务的一系列资源。确定账户-区域-服务的一系列资源构成产品的最小单元。在此最小单元的颗粒度定在服务而非资源是因为过小的颗粒度会影响产品定义和部署效率。我们把产品的最小单元称为“块”。更复杂的产品都可以由不同的块像搭积木一样拼叠而成。
产品定义的最小单元就是块,基于此可以构建可大可小的产品架构。块是相同服务不同资源的集合。资源之间存在依赖关系。一个块内相同服务资源的依赖称为块内依赖,例如 IAM 的角色依赖客户策略,身份中心的目录组依赖权限集。由于不同服务的资源必定属于不同的块,所以块之间也存在依赖关系。不同块之间不同服务资源的依赖称为块间依赖,例如先有 KMS 密钥之后才能用来加密 S3 桶,先有 IAM 角色之后才能用来让 Lambda 函数代入等。存在依赖关系的块需要依次创建,不存在依赖关系的块可以同时创建。我们以 2023 年 9 月博客[1]的产品“由自动扩缩组管理实例的弹性堡垒机架构”来举例。该产品主要包含 4 个块涉及 4 种服务(IAM,VPC,EC2,自动扩缩)。其中 EC2 块依赖 IAM 块的角色,自动扩缩块依赖 EC2 块的启动模板,而 IAM 块和 VPC 块无依赖关系。据此我们排列如下图所示的构建先后次序。
图 1. 由自动扩缩组管理实例对弹性堡垒机架构分阶段拆解
如果仔细观察上图会发现其仿佛一条流水线,阶段内的块可并发执行,各阶段则依次执行。如此即能加快执行速度,又可满足块之间依赖关系。第一阶段包含所有不依赖其他块的块。从第二阶段开始,其包含的块依赖前一阶段所含块。用 P 代表产品,S 代表阶段,b 代表块,则 S = {b1, b2, …, bm},产品可以表示为 P = {S1, S2, …, Sn},其长度可以表示为 |P| = n。给定一定数量的块及其依赖关系 bi < bj,定义产品的最优解可以转化为如何使得产品长度最小化的问题。
故此我们可将产品块及其先后次序映射至 CodePipeline 流水线的相关组件:块映射为“操作”,并发执行的块集合映射为“阶段”,而一个产品所有块的有序执行映射为“管道”。进一步用数学符号来抽象,一个产品可以表示成元素为块的二维数组。第一维数组是顺序的阶段,第二维数组则是并发的块。例如上图可以表示为 “[[IAM, VPC], [EC2], [自动扩缩]]
”。
产品定义的基本结构是二维数组,根据依赖关系排列可构建“合适”的产品结构。产品合适的度您可根据实际业务需求进行合理设计,可简单或复杂。根据流水线的限额,单个阶段包含的产品块不能超过 50,单个产品包含的阶段不能超过 50,所以块总数上限为 2500。
产品运维操作
了解产品定义的最小单元和基本结构后,以下我们以着陆区建设经常涉及的访问权限控制资源为例,介绍产品日常运维操作流程。相关资源定义的具体关键字含义请参考《Cloud Foundations 产品定义规范》,在此不再赘述。截至目前产品工厂支持 23 类亚马逊云科技服务的 40 种云资源。
定义产品
假设根据某综合医院业务要求,需在 Cloud Foundations 创建的基础着陆区之上于某成员账户为肿瘤部新建用于 EC2 实例和 Lambda 函数的两服务角色,授权读取相关肿瘤数据存储桶。其中 EC2 角色还有只看和所有 Lambda 权限。在身份中心另需新建肿瘤数据查看权限集和对应目录组。
[
[
{
"accounts": ["123456789012"],
"service": "iam",
"policies": {
"s3-oncology": {
"inline": [{
"actions": ["s3:ListBucket*", "s3:GetBucket*"],
"resources": ["arn:${PARTITION}:s3:::my-oncology-data-123456789012"]
}, {
"actions": ["s3:GetObject*"],
"resources": ["arn:${PARTITION}:s3:::my-oncology-data-123456789012/*"]
}]
}
},
"roles": {
"ec2-oncology": {
"trusts": ["ec2"], "customer": ["s3-oncology"],
"managed": ["ViewOnlyAccess"], "services": ["lambda"]
},
"lambda-oncology": {"trusts": ["lambda"], "customer": ["s3-oncology"]}
}
}
],
[
{
"service": "sso",
"permissions": {
"s3-oncology": {"customer": ["$.s3-oncology"], "managed": ["ViewOnlyAccess"]}
},
"groups": {"s3-oncology": {"s3-oncology": ["123456789012"]}}
}
]
]
根据上述要求和产品工厂 IAM 及身份中心有关资源规范,定义该访问控制产品如上代码段所示(您需更改目标账户为合法账户)。我们把产品分为两阶段,首阶段定义客户策略 s3-oncology 和两服务角色 ec2-oncology, lambda-oncology,次阶段定义身份中心权限集和目录组 s3-oncology。下图以细虚线标注块内依赖,以粗虚线标注块间依赖。IAM 不分区域部署,故省略区域信息;身份中心默认于主区域的安全账户部署,故省略账户和区域信息。在定义中我们使用预置环境变量${PARTITION}
。尽量不使用硬代码有利于在多环境复用。
图 2. 访问权限控制块内块间依赖关系示意
部署销毁产品
参考《Cloud Foundations 用户使用手册》第十一节,主要步骤如下:
- 以 parameter-editor 角色新建名为 product-ac-oncology 的产品应用配置文件;
- 以 catalog-user 角色启动产品,产品名称和配置文件都是 product-ac-oncology,阶段和变量取默认值;
- 以 pipeline-approver 角色执行并批准流水线 pipeline-product-ac-oncology-apply-fresh;
- 代入部署账户确认一个策略和两个角色创建完成;
- 代入安全账户确认权限集和目录组创建完成。
销毁产品的顺序和部署过程相反,依次为:
- 以 pipeline-approver 角色执行并批准流水线 pipeline-product-ac-oncology-destroy;
- 代入部署账户确认一个策略和两个角色删除完成;
- 代入安全账户确认权限集和目录组删除完成;
- 以 catalog-user 角色终止产品 product-ac-oncology;
- 以 parameter-editor 角色删除产品应用配置文件 product-ac-oncology。
多阶段产品运维操作
上一节我们介绍了通过产品工厂为肿瘤部门定义相关访问权限控制资源并部署销毁的全过程。对于真实业务需求来说,需要准备访问权限控制的部门可能有很多,例如门诊部、住院部等等。假设各部门对各自数据有类似的访问权限要求,简单的做法是将上述产品定义文件复制多份,对其中的桶名关键字和成员账户进行替换。然而此种方式会造成很多冗余和硬代码,不利于后期大批量维护。更佳的做法是借助产品工厂的阶段和变量属性灵活更新相应值,通过单一产品定义动态生成适应多部门的访问权限控制资源。在此阶段可以视为一个特殊的变量,通过${STAGE}
引用。
定义产品
我们把成员账户和部门名称作为阶段和变量抽象出来,分别使用 STAGE 和 DEPARTMENT 代替,更新的产品定义如下所示。
[
[
{
"accounts": ["${STAGE}"],
"service": "iam",
"policies": {
"s3-${DEPARTMENT}": {
"inline": [{
"actions": ["s3:ListBucket*", "s3:GetBucket*"],
"resources": ["arn:${PARTITION}:s3:::my-${DEPARTMENT}-data-${STAGE}"]
}, {
"actions": ["s3:GetObject*"],
"resources": ["arn:${PARTITION}:s3:::my-${DEPARTMENT}-data-${STAGE}/*"]
}]
}
},
"roles": {
"ec2-${DEPARTMENT}": {
"trusts": ["ec2"], "customer": ["s3-${DEPARTMENT}"],
"managed": ["ViewOnlyAccess"], "services": ["lambda"]
},
"lambda-${DEPARTMENT}": {"trusts": ["lambda"], "customer": ["s3-${DEPARTMENT}"]}
}
}
],
[
{
"service": "sso",
"permissions": {
"s3-${DEPARTMENT}": {
"customer": ["$.s3-${DEPARTMENT}"], "managed": ["ViewOnlyAccess"]
}
},
"groups": {"s3-${DEPARTMENT}": {"s3-${DEPARTMENT}": ["${STAGE}"]}}
}
]
]
部署销毁产品
我们按部门逐一定义部署资源,首先从肿瘤部开始。假设上一节有关肿瘤部的全部资源已经销毁干净:
- 以 parameter-editor 角色新建名为 product-ac-s3data的产品应用配置文件;
- 以 catalog-user 角色启动产品,产品名称为 product-ac-oncology,配置文件为 product-ac-s3data ,阶段为 123456789012,变量为
{"DEPARTMENT": "oncology"}
; - 以 pipeline-approver 角色执行并批准流水线 pipeline-product-ac-s3data-oncology-apply-fresh;
- 代入部署账户确认一个策略和两个角色创建完成;
- 代入安全账户确认权限集和目录组创建完成。
由上述步骤举一反三可以为门诊部和住院部及其对应成员账户利用相同的产品定义配置文件部署不同的访问权限控制资源,如下表所示。在此不再赘述留给读者自行练习。
部门 | 产品名称 | 阶段 | 变量 |
门诊部 | product-ac-clinic | 123456789013 | {"DEPARTMENT": "clinic"} |
住院部 | product-ac-inpatient | 123456789014 | {"DEPARTMENT": "inpatient"} |
销毁产品的顺序和部署过程相反,依次为:
- 以 pipeline-approver 角色执行并批准流水线 pipeline-product-ac-s3data-oncology-destroy;
- 代入部署账户确认一个策略和两个角色删除完成;
- 代入安全账户确认权限集和目录组删除完成;
- 以 catalog-user 角色终止产品 product-ac-oncology;
- 重复上述步骤销毁及终止所有基于配置文件 product-ac-s3data 的产品;
- 以 parameter-editor 角色删除该配置文件。
构建账户创建蓝图
从上一节多阶段产品运维操作可以看出,灵活运用阶段和变量可以为单个产品定义构建多重部署。当把阶段指定为账户号码时,产品部署可以视为对该账户进行资源创建过程。我们将此类产品定义称为账户创建蓝图。例如,您可以针对不同类型账户准备相应蓝图产品定义 blueprint-*,当账户工厂创建好账户之后,通过启动相应蓝图定义并以新建账户号码为阶段,您可以轻松实现账户自定义标准化过程,类似于 AWS Control Tower 的账户工厂自定义工具(AFT)。不同的是对一个账户而言 AFT 只能适用一张蓝图,而 Cloud Foundations 可以同时适用多个蓝图产品。
总结
本文主要介绍了 Cloud Foundations 新增功能产品工厂的设计思想和基本结构。并以着陆区常见的访问权限控制资源为例,详细演示了产品运维操作,包括如何定义、部署和销毁。我们还讨论了利用产品的多阶段特性,通过阶段和变量抽象共通的属性,简洁高效地为多部门相关访问控制资源进行大批量运维管理。更多详细信息可以参考配套的《用户使用手册》和《产品定义规范》。
推而广之,您可以利用产品工厂基于广泛的亚马逊云科技服务和资源构建更多更复杂的产品及架构,使得云基础设施所有产品资源完全被定义、自动化和标准化。产品科学定义和有效利用的标准之一是高质量的服务您的业务需求和生产实际。Cloud Foundations 会不断更新,支持更多服务和资源,助力您在云资源标准化管理自动化运维方面的各种构建需求。
参考资料
- 博客:借助 Cloud Foundations 一键部署弹性堡垒机安全合规地实现会话管理及端口转发,2023-09
- 博客:借助 Cloud Foundations 实现多账户组织云上网络环境两种共享模式的整体规划与一键部署,2023-02
- 博客:借助 Cloud Foundations 规划设计云上多区域网络轴辐拓扑结构一键部署东西南北流量分别或合并检查,2023-11
- 博客:借助 Cloud Foundations 共享网络产品于多个网络账户规划设计并一键部署云上跨区域互联的多张网络,2024-02