亚马逊AWS官方博客
基于 IAM 权限边界的 SCP 替代方案
背景
亚马逊云科技多账户结构体系能够让企业安全、快速地扩展云上业务,是亚马逊云科技在实践经验中总结出来的云上安全最佳实践。其中Organizations 服务可帮助用户集中管理和治理云上多账户环境。借助亚马逊云科技 Organizations 服务提供的服务控制策略 (Service Control Policies,SCP)功能,管理员可集中管理并定义账户的最大可用权限,以确保云上账户符合企业的安全规范。
在本文撰写之时,亚马逊云科技 Organizations 的 SCP 功能还未在中国区(北京区和宁夏区)上线。但是在众多企业级云上账户和安全设计中,SCP 仍然是企业安全部门需要衡量的一个重要且不可或缺的功能。
在中国区实现 SCP 功能的替代方案中实现了对新创建 IAM 实体的 SCP 策略自动绑定。本方案中借鉴了此部分设计思想,并结合多个项目实施经验,扩展支持以下功能:
- 支持针对账户中已有的 IAM 实体的 SCP 策略绑定
- 参考原生 SCP 设计理念,支持包括基于账户级别和 Organizations 组织单元级别的 SCP 策略配置
- 通过 S3存储桶的事件通知功能,当 SCP 策略文件有更新时,支持自动更新至 IAM 实体关联的权限边界策略中
- 支持 IAM 实体自定义的 IAM 权限边界策略
- 基于 CloudFormation 的全自动部署模式,简化部署流程
- 基于 Service Catalog 的 SCP 账户初始化流程,减轻运维负担
本文将会详细介绍基于 IAM 权限边界(IAM Permission Boundary)设计的 SCP 替代方案的原理和实现。方案中所涉及代码已开放在 https://github.com/aws-samples/scp-alternative-solution
访问控制逻辑
在深入了解 SCP 替代方案之前,先理解下 IAM 权限边界和 SCP 在云上访问控制中承担的作用。
在提供 SCP 功能的前提下,以上流程图展示了单个账户内部的访问控制逻辑,在多账户体系中还需考虑跨账户的访问要求。感兴趣读者可参考文档详细阅读。
从原理上看,在多账户体系中的访问控制逻辑中,IAM 权限边界和 SCP 具有类似的功能,二者都定义了所允许操作的最大权限集。最大不同之处是 SCP 所定义的权限是针对账户级别的,而 IAM 权限边界是针对单个 IAM 用户和角色。
因此在本文设计的 SCP 替代方案中,核心思想是通过自动化的架构设计,将原本设置在账户级别的 SCP 策略,配置在目标账户下所有的 IAM 用户和角色所对应的 IAM 权限边界中,来达到类似 SCP 提供的功能。
方案设计
在亚马逊云科技 Global 区域中,若在 Organizations 服务中使用了 SCP 功能,可以将相应的 SCP 策略应用到 Organizations 的组织单元或者某一个具体的账号下。在 Organizations 的组织单元中添加新的账户时,该组织单元下定义的 SCP 也会自动应用到新账号中。因此,对于 SCP 的替代方案,主要来实现三个场景的策略绑定:
- 为 Organizations 中已有的账号应用 SCP 规则
- 为 Organizations 中的组织单元应用 SCP 规则
- 允许更新对应账户或者组织单元的 SCP 规则
前提条件
根据云上多账户体系的最佳实践,在一个最小的多账户结构中,至少包含安全(Security)账户,管理(Management)账户等多个核心账户,以及其他多个成员账户(Dev/QA/PROD)。
此 SCP 替代方案默认要求:
- 用户现有环境是一个多账号体系,并且包含一个安全账户。由于 SCP 是针对账户界别的安全的配置,一般由安全管理员进行更新维护,因此该方案中所需要基础设施服务也将会部署在安全账户中。
- 通过管理账户能够以的方式访问各个成员账户,并以管理员身份操作该成员账户下的资源。如果成员账户是通过 Organizations 创建,用来切换角色的名称默认会是OrganizationAccountAccessRole ,用户在部署时也可指定其他角色名字。在成员账户下应用了 SCP 策略之后,该角色将不会应用 SCP 策略。
- 允许安全账户以切换角色的方式访问到管理账户,并有权限以切换角色的方式访问各个成员账户。此方案设计中,通过安全账户来管理成员账户下的资源,首先以切换角色方式访问管理账户,再通过管理账户中赋予的角色以切换角色的方式访问到各个成员账户。
总体架构设计
该架构设计目的是尽可能提供类似于原生 SCP 提供的功能,同时也会尽可能考虑减小将来迁移到原生SCP 功能所带来的额外工作量。详细架构设计如下所示:
根据上述的三个 SCP 策略绑定场景,结合亚马逊云科技提供的原生服务,设计以上架构模型。主要服务配置如下:
- S3 存储桶 :用于存放 SCP 自定义策略。在原生 SCP 的配置过程中,用户可以通过控制台针对 SCP 策略文件直接进行编辑、更新等。在此替代方案设计中,SCP 策略文件的更新在安全账户的一个专用的 S3 存储桶里完成,并配置相对应的事件通知,由自定义的 Lambda 函数完成账户内 IAM 权限边界策略的更新。同时,存储在该 S3 存储桶里的 SCP 策略文件需要符合一定的命名规范,后面将做详细介绍。
- Service Catalog:提供一个用户接口,让管理员手动注册并初始化需要绑定 SCP 策略的账户。在针对原生 SCP 策略的绑定过程中,用户可以在控制台通过 Organizations 服务创建出来的账户结构,将对应的 SCP 策略绑定到相应的账户或者组织单元中。在此替代方案设计中,所有需要绑定 SCP 策略的账户,均需要通过这个 Service Catalog 手动注册并初始化该目标账户。
- Event Rule 和 CloudTrail:持续监控账户内新创建的 IAM 用户或者角色的 API 活动,并把事件发送到安全账户的 Lambda 做处理 ,将新创建的 IAM 用户和角色应用 IAM 权限边界。在原生 SCP 功能中,SCP 策略是应用于整个账户的,新创建的 IAM 用户和角色将自动应用 SCP 策略。由于该方案是基于 IAM 权限边界,每次有新用户或者角色创建,通过这种机制保证新创建的用户或角色也应用 IAM 权限边界。
- Lambda 函数:
- scp-account-register:用于注册并初始化需要绑定 SCP 策略的账户,并将账户信息存入 DynamoDB,供其他 Lambda 函数查询账户元信息使用
- scp-iam-event-dispatcher:用于接收已注册账户中的新创建的 IAM 用户和角色的事件,并将对应的 IAM 权限边界应用于新创建的 IAM 用户或者角色中
- scp-s3-event-dispatcher:用于接收 S3 存储桶里策略文件更新的事件,并根据 SCP 策略文件更新的内容,自动将变更的 SCP 策略文件更新在对应账户里的 IAM 权限边界里
- SNS:用于接收 SCP 策略创建以及绑定过程中失败的信息,安全管理员可以订阅该 SNS 主题,及时收到通知
- DynamoDB:用于存放注册的账号元信息,供 Lambda 执行时查询使用。存放的信息格式如下:
AccountId | MgtId | OuId | ScpCustomPolicyList (L) | ScpPolicyPathList (L) | ScpUpdateTime (S) |
1123456789 | 2123456789 | OU-abcd-xxxxxxxx | [ { “S” : “arn:aws-cn:iam::1123456789:policy/CustomPermissionBoundaries” }] | [ { “S” : “permission-boundary-policy/ou-abcd-xxxxxxxxx.json” }] | Tue Jul 20 11:00:38 2021 |
总体上来看,为了实现前面所述的三个策略绑定场景,从操作流程角度,上述架构可以拆分成以下三个方面进一步详细说明:
- 对成员账号进行初始化设计
- 对成员账号下新建 IAM 用户和角色的 SCP 策略自动绑定设计
- SCP 策略文件的更新设计
对成员账号进行初始化设计
在应用 SCP 的策略之前,一般情况下,用户已经拥有了一些核心账号以及一些工作负载的账号。针对已存在的账号,设计通过 Service Catalog、CloudfFormation 以及 Lambda 来实现对已存在的成员账户进行初始化,其中包括针对该账户已有的 IAM 用户和角色进行 SCP 策略的绑定。详细的架构如下图所示:
对已有账号进行初始化的基本逻辑如下:
- 安全管理员登录到安全账号,进入到 Service Catalog 的产品页面,找到创建好的 SCP Account Register 产品
- 启动一个新的产品,输入需要应用 SCP 的账号 ID 以及该账号所属的组织单元 ID
- 此时 Service Catalog 将启动一个 CloudFormation 的堆栈,在此堆栈中,将创建一个 Lambda 函数做主要逻辑处理
- Lambda 执行过程中,将会从 S3 存储桶中获取已定义好的 SCP 策略文件(这里会通过输入的账户 ID 和组织单元 ID 匹配相应的策略文件)
- 将成员账号的基本信息(包括账户 ID 以及所对应的 SCP 策略文件路径等)添加到 DynamoDB 里
- 根据获取到的策略文件生成 IAM 权限边界策略。如果该账户的 IAM 用户或者角色中,已经应用了自定义的 IAM 权限边界,这里会将通过 SCP 策略文件中定义的权限边界合并到该用户或者角色已经存在的 IAM 权限边界策略中
- Lambda 执行过程中,在成员账户中创建所需要的 CloudTrail,事件规则,来持续监测账号内新创建的 IAM 用户和角色。在下一小节<对成员账号下新建 IAM 用户和角色的 SCP 策略自动绑定设计> 中将做详细介绍
- Lambda 执行过程中有异常退出,可通过 SNS 发送给安全管理员
对成员账号下新建 IAM 用户和角色的 SCP 策略自动绑定设计
对成员账号下已有的 IAM 用户和角色应用了 SCP 策略之后,后续在该成员账户下也会新创建一些 IAM 用户或者角色。此时也需要保证 SCP 策略应用于成员账号下新创建的 IAM 用户和角色。在这种场景下,通过成员账户下已经部署的事件规则来捕捉新创建 IAM 用户和角色的事件,并将该事件通过事件总线最终发送到安全账户下的 Lambda 函数,由 Lambda 来实现对成员账号下的新增 IAM 用户或者角色的 IAM 权限边界的绑定。其基本逻辑如下:
- 成员账号的管理员或者用户,由于实际需要,通过亚马逊云科技控制台或者 CLI 创建了一个新的 IAM 用户或者角色
- 通过已配置好的 CloudTrail 监听账户内的活动
- 通过已配置好的事件规则捕获到新创建 IAM 用户或者角色的 API 请求
- 通过成员账户的事件总线将该事件发送到配置好的安全账号下的事件总线中
- 安全账号中的事件规则捕获到成员账号的 IAM 事件后,发送到 SQS 中
- 通过 SQS 触发一个scp-iam-event-dispatcher 的 Lambda 函数
- 该 Lambda 从安全账号的 S3 存储桶中获取对应的 SCP 策略文件
- 从 DynamoDB 中获取成员账号信息
- 在成员账号中,根据最新获取到的 SCP 策略文件更新对应的 IAM 权限边界策略,完成对于新创建的 IAM 用户或角色 SCP 的策略绑定
- 如果 Lambda 执行过程中有异常退出,可通过 SNS 发送给安全管理员
SCP 策略文件的更新设计
由于安全需求的变更,安全管理员也需要能够对 SCP 的策略进行随时更新。在这种场景下,通过 S3 存储桶配置好的事件触发器以及 Lambda 来实现 SCP 策略文件在各个成员账户下的自动更新。基本流程如下:
- 安全管理员在本地更新好 SCP 的策略文件,并将其上传到存储 SCP 策略的 S3 存储桶中
- 上传新的 SCP 策略后,已配置好的 S3 事件规则将被触发,并将事件信息发送到 SQS 中
- SQS 接收到事件信息后,会触发一个更新成员账号 SCP 策略的 Lambda
- 该 Lambda 函数从 DynamoDB 中获取帐号的的元信息
- Lambda 根据新的 SCP 策略和账号信息,访问到各个成员账号完成 IAM 权限边界策略的更新
- 如果 Lambda 执行过程中有异常退出,可通过 SNS 发送给安全管理员
部署步骤
该方案中所需要的基础设施,由 CloudFormation 模版进行自动化部署。需要在管理账户和安全账户下分别部署。
打包部署代码
下载代码仓库至本地,并切换至代码根目录,执行 make 命令,在 assets目录下将生成所需要部署的模版和 Lambda 压缩包文件。
➜ make
zip assets/scp-s3-event-dispatcher.zip lambda/scp-s3-event-dispatcher.py
updating: lambda/scp-s3-event-dispatcher.py (deflated 74%)
zip assets/scp-iam-event-dispatcher.zip lambda/scp-iam-event-dispatcher.py
updating: lambda/scp-iam-event-dispatcher.py (deflated 77%)
zip assets/scp-account-register.zip lambda/scp-account-register.py
updating: lambda/scp-account-register.py (deflated 77%)
cp -f cloudformation/scp-service-catalog-product-template.yaml assets/scp-service-catalog-product-template.yaml
管理账户下的部署
登陆管理账户,选择 CloudFormation 模版文件 010 , 创建一个允许安全账户代入到管理账户的 IAM 角色。关键部署参数如下:
- ManagementAccountAccessRoleName:部署在管理账户的角色名称,用来允许安全账户切换角色到管理账户
- OrganizationAccessRoleName:部署在所有成员账户的角色名称,用来允许管理账户切换角色到各个成员账户
- SecurityAccountID:安全账户 ID
安全账户下的部署
切换至安全账户,执行以下部署:
- 选择 CloudFormation 模版文件 020, 创建一个用于 CloudFormation 部署的一个 S3 存储桶。
- 前面打包部署代码中已经创建好了 assets文件,将 assets 目录下的所有文件,上传到上述 S3 存储桶的根目录下。
- 选择 CloudFormation 模版文件 030,创建所需要的基础设施资源。关键部署参数如下:
- ManagementAccountID: 管理账户 ID
- ManagementAccountAccessRoleName:部署在管理账户的角色名称,用来允许安全账户切换角色到管理账户(在管理账户下部署时会有同样的模版参数,要求输入的值保持一致)
- OrganizationAccessRoleName:部署在所有成员账户的角色名称,用来允许管理账户切换角色到各个成员账户(在管理账户下部署时会有同样的模版参数,要求输入的值保持一致)
- SCPCatalogAdministrator:部署在安全账户下的用户或者角色名称,此用户或者角色将作为 SCP Account Register 的 Service Catalog 产品的管理员:
- 针对IAM 用户的输入值:例如user/Alice
- 针对IAM 角色的输入值:例如role/Operation
使用说明
在部署成功之后,SCP 替代方案所需要的基础设施均已创建完成,用户可以根据自己需求上传准备好的 SCP 策略文件、注册并初始化需要应用 SCP 策略的账户等。下面就其中几个关键的操作场景做详细说明。
场景一:对已有成员账号的初始化
任何需要绑定 SCP 策略的账户,首先需要在 Service Catalog 产品里注册并初始化该账户。
- 进入到安全账户,找到用于存放 SCP 策略文件的 S3 存储桶,默认命名规则是:scp-alt-<Security-Account-ID>。
- 将准备好的 SCP 策略文件按照命名要求重新命名(例如:本次测试环境中将010-region-beijing-only.json 命名为ou-47kj-8dquliyv.json):
注意:SCP策略文件需要存放在安全账号的 S3 存储桶的permission-boundary-policy路径下,文件对象命名规则为:
- 单个账户级别策略文件命名:account-<ACCOUNT-ID>.json
- 组织单元级别策略文件命名:<OrganizationUnit-ID>.json
- 在 S3 存储桶里新创建目录permission-boundary-policy,上传 SCP 策略文件至 S3 存储桶的 permission-boundary-policy 目录
- 进入到安全账号,点击进入到Service Catalog,选择 SCP Account register 产品,并点击 启动产品
-
- 输入产品名称,例如:enroll-account-0123456789012
- 输入需要注册成员账户的账户 ID,例如:0123456789012
- 输入该成员账号所属的组织单元 ID(OrganizationUnitID),例如:ou-47kj-8dquliyv
-
- 等待执行完成后,可以看到产品启动成功,变为可用状态
- 以OrganizationAccountAccessRole 角色登录到成员账号,可以看到新创建一个 IAM 策略 scp-enforce-policy, 并且作为 IAM 权限边界应用到所有 IAM 用户或者角色上。注意,默认 OrganizationAccountAccessRole 将保留作为管理员运维角色,不会应用 SCP 策略。
- 以非管理员身份进入到成员账号,根据 SCP 定义内容,测试是否符合预期。
-
- 如果使用的提供的测试 SCP 文件010-region-beijing-only.json 。预期结果是该成员账户下的用户或者角色只能在北京区操作相关资源,宁夏区相关操作将被拒绝。
-
场景二:对 SCP 策略进行更新
当用户需要对 SCP 的某些策略进行更新时,首先需要对相关的策略文件进行修改,然后将更新后的 SCP 策略文件根据要求的命名格式上传到存放策略的 S3 存储桶中。
- 根据要求修改 SCP 策略文件内容,并确保 SCP 策略文件符合以下命名规范例如(本次测试环境中将020-deny-create-S3-bucket.json 命名为 ou-47kj-8dquliyv.json):
注意:自定义的 SCP 策略默认需存放在安全账号的 S3 存储桶的 permission-boundary-policy 路径下,文件命名规则为:
- 单个账户级别策略文件命名:account-<ACCOUNT-ID>.json
- 组织单元级别策略文件命名:<OrganizationUnit-ID>.json
- 进入到安全账户,将更新的 SCP 策略文件,上传到存放策略的 S3 存储桶中,直接覆盖原策略文件即可。
- 以非管理员身份进入到成员账号,根据 SCP 策略文件更新内容,测试是否符合预期。
-
- 如果使用的提供的测试 SCP 文件020-deny-create-S3-bucket.json。预期结果是该成员账户下的用户或者角色不能操作任何 S3 资源。
-
场景三:对新建 IAM 用户和角色进行 SCP 策略绑定
在某些场景下,用户需要根据需求在成员账号中通过控制台或者 CLI 等创建新的 IAM 用户或角色。该方案会通过对账户中 IAM 的事件监控来对新建的 IAM 用户或者角色自动应用已定义好的 SCP 策略。
-
- 登录到成员账号,创建一个 IAM 用户或角色
- 持续观察该用户或角色的 IAM 权限边界 配置
- 可以看到 IAM 权限边界 策略scp-enforce-policy 成功应用于新创建的用户或角色上。
注意事项
由于该替代方案是基于 IAM 权限边界实现的,在使用过程中也会存在一定的限制和注意事项:
- 由于每个 IAM 用户或者角色只能应用一个 IAM 权限边界策略,根据官方文档,单个 IAM 权限策略内容不能超过 6,144 个字符。
- 该方案暂不支持类似 SCP 的策略继承功能。需要针对 Organizations 中每一级组织单元在 S3 存储桶里分别定义策略文件。
- 为了满足 SCP 替代方案使用条件,相比用户自定义的 SCP 策略,最终在账户内创建出来的 IAM 权限边界会自动增加以下权限控制内容:
- 对于部署在成员账户中的,服务于 SCP 替代方案的基础设施资源,策略绑定过程中,同样也会默认自动加入 Deny 的语句声明。
- 根据文档,CloudTrail 不能保证 API 事件传达的实时性 (一般情况下会控制在 15 分钟之内)。在极少数条件下可能会出现新创建的 IAM 实体延时绑定 IAM 权限边界。对于实时性要求比较高的场景,建议在 SCP 默认策略中拒绝创建新的 IAM 用户或者角色。
- SCP 替代方案中策略绑定逻辑由部署在安全账户的多个服务共同完成。为了避免安全账户内部因为 SCP 策略绑定而影响服务的执行,特别在 Service Catalog 产品中禁止针对安全账户的 SCP 账户初始化操作。
- SCP 策略绑定过程中,需要访问成员账户,对成员账户里的 IAM 权限边界进行相关操作。为了避免成员账户因为 SCP 策略绑定影响 IAM 的相关操作,成员账户中需要至少保留一个管理员角色,该角色将不会应用任何 SCP 策略。默认角色是OrganizationAccountAccessRole,用户可在 CloudFormation 部署过程中通过参数OrganizationAccessRoleName指定其他角色名称。
总结
在中国区没有 SCP 原生服务的情况下,用户可通过该方案,快速的为多账户体系下的成员账号进行权限控制,为企业构建一个更安全可靠的云上环境。
同时随着中国区服务的不断更新,我们建议当中国区的原生 SCP 功能发布后,客户应尽快从 SCP 替代方案迁移到亚马逊云科技 Organiztations SCP 原生功能上。
参考
- https://thinkwithwp.com/cn/blogs/china/permission-boundary-based-authorization-restriction-method-for-multi-account-management/
- https://thinkwithwp.com/cn/blogs/china/alternatives-to-implementing-scp-functionality/