ARTICLE DETAIL

资讯详情

深耕商务建站与企业官网运营的一线实战洞察。

AWS Landing Zone自动化与测试:从Terraform到多账号治理

AWS Landing Zone自动化与测试:从Terraform到多账号治理 简介面向AWS架构师与DevOps工程师这份资源汇集了AWS Landing Zone自动化与测试的可复用代码和操作文档。核心覆盖测试环境搭建、AWS Organizations组织与OU创建、Core账户初始化及安全基线配置适用于企业级多账户治理和云环境合规落地场景。资源共69个文件主要为json策略模板、yml配置模板、md说明文档另含少量Ruby辅助脚本与测试脚本整体约1.85MB。其中json用于定义IAM权限与SCP策略yml用于CloudFormation及Config规则md则梳理了环境准备与操作流程结构清晰便于按模块查阅。目前已有310人学习下载。通过压缩包可快速获得CloudFormation工具、多层级VPC模板、CloudTrail和VPC Flow Logs配置示例以及组织管理、联邦访问、成员账户治理等脚本能显著缩短Landing Zone环境搭建与验证周期。1. AWS Landing Zone 的复杂度不在搭建而在自动化与测试提到 AWS Landing Zone落地区很多团队的第一反应是“搭一次就完事”把组织、账号、预算和日志中心创建出来然后开始跑业务。我在实际交付里反复看到一个翻车画面——过了半年安全基线升级或业务要新开一个账号脚本一重放网络与权限规则被冲得七零八落没人说得清哪条参数是哪一轮变更留下的。Landing Zone 的本质不是一次性搭建而是一套需要被自动化、被测试、被反复重放的云上基建骨架。这篇笔记沿着“自动化什么 → 用什么代码落地 → 怎么验证 → 踩过哪些坑”往下走配可直接抄下来的命令与参数解释适合负责多账号治理、正在为审计准备配置证据的从业者。2. 自动化的到底是什么组织、身份与审计日志三条主线Landing Zone 不等于一台虚拟机或一份配置文件它是一组多账号环境的治理基线。自动化改造的第一步不是写代码而是搞清楚哪些东西必须被“版本化”。我在项目里见过不少团队把精力花在自动创建账号上却忽略了账号周边那些真正决定安全边界的绑定关系结果环境看起来自动化了治理却失控了。2.1 先分清自动化对象组织、身份与日志三条主线第一层是组织OrganizationOU 树、服务控制策略SCP、账号的注册与移入移出。这一层解决的是“某个账号在什么权限边界内运行”。第二层是身份统一身份中心或 SSO权限集Permission Set与账号的绑定关系。这一层解决的是“谁可以进哪个账号、拿到什么角色”。第三层是审计与合规集中日志账户、S3 日志桶、CloudTrail 和 Config 的投递关系。这一层解决的是“出了事能不能查、查到的证据是否完整”。很多刚接触的人把“Landing Zone 自动化”理解为“自动建账号”这是误区。账号只是入口真正需要被重放的是围绕账号的绑定关系和安全规则。一个新建账号如果忘记绑定权限集或者没被移入正确的 OU它就在治理范围之外。账号工厂的自动化和这三条主线是绑定的账号创建成功的定义应该是“账号已存在、已加入正确 OU、已绑定默认权限集、日志已开始投递”而不是仅仅收到一个创建成功的回执。2.2 三条自动化路线放在同一张表里看边界控制台手工操作、CLI/SDK 脚本、基础设施即代码这三条路线各有适用场景。落地实践中它们不是互斥关系但最终能不能“被测试”差别很大。路线适用阶段状态管理可测试性主要风险控制台手工点一次性探索 / 小型演示环境无无漏配、不可重放CLI/SDK 脚本批量迁移 / 临时操作弱脚本级重复执行会重复创建基础设施即代码长期治理 / 变更管理有状态文件强学习曲线高控制台和 CLI 脚本的共同问题是没有状态。你不知道哪些资源是脚本创建的哪些是另一个人手工改过的环境一旦变大排查就变成考古。IaC 的核心价值不只是“用代码描述资源”而是把状态文件作为唯一事实来源后面才谈得上自动化测试。我一般建议团队把 Landing Zone 的骨架用 Terraform 或 CloudFormation 管理控制台只留给紧急排查CLI 脚本可以留着做一次性运维但不要把关键变更押在临时命令上。2.3 动手前先摸底三条 AWS CLI 确认命令任何代码化改造之前先把现状摸清楚。这里假设你已经用 CLI 配置好了凭证并且有 Organizations 的读取权限。三条命令分别覆盖“根”“OU”“账号归属”这是后面写代码要依赖的三种数据。# 1. 查看当前组织结构和根OU信息 aws organizations list-roots --output table # 2. 查看现有OU列表确认逻辑分层是否合理 aws organizations list-organizational-units --parent-id r-xxxx --output table # 3. 查看账号列表以及每个账号所在的OU for id in $(aws organizations list-accounts --query Accounts[?StatusACTIVE].Id --output text); do echo Account: $id aws organizations list-parents --child-id $id --output text done第一条命令返回组织的根 ID通常形式是r-xxxx。第二条命令的--parent-id要填上一条命令查到的根 ID返回当前根下直接挂着的 OU。第三条命令遍历所有活跃账号逐个查询父节点如果账号挂在 OU 下面返回 OU ID如果账号直接挂在根下返回根 ID。很多历史项目里会看到一批账号直接挂在根下这意味着它们不受任何 OU 层级的 SCP 约束把它们重排进 OU 正是自动化改造的第一步。在实际操作中我会把摸底结果存成 JSON 快照放进仓库的baseline/目录后续测试断言直接读这份快照。这样第一次交付就形成了基线后面每一次变更都能对照它做差异分析而不是靠记忆判断环境是否漂移。3. 把 Landing Zone 写进代码Terraform 模块拆分与最小可跑样例选 Terraform 不是因为它比 CloudFormation 酷而是因为测试这件事在 Terraform 生态里更成熟。这一章从选型理由讲到模块拆分再落到一段能跑的最小代码以及批量接入账号的两种方式。3.1 为什么选 Terraform 而不选 CloudFormation状态、测试与迁移成本Terraform 的terraform plan天然是一份 diff 报告能直接输出成 JSON 放进测试流程state文件把资源归属讲得很清楚。CloudFormation 是云平台原生能力不用额外维护状态锁但它的变更集要回控制台查看脚本化不如 Terraform 顺手。对于已有大量 CloudFormation 的团队不必推翻更常见的做法是用 Terraform 管 Landing Zone 骨架CloudFormation 留给业务应用。两者不冲突很多团队把 SCP、OU 和权限集用 Terraform 管理业务栈继续用 CloudFormation互不干扰。这里要注意一个认知Landing Zone 一旦引入 Control Tower 这类托管服务Terraform 直接新建的资源会被托管服务接管一部分生命周期。比如 Control Tower 会强制管理某些 SCP 或日志投递。代码里要对这类被托管资源做只读声明或配置lifecycle否则每次 plan 都会看到平台侧做出的变更被标记为漂移。这一块是后面避坑章第一个大坑的来源提前理解可以省掉很多排查时间。3.2 模块拆分组织、身份、日志与安全三块怎么切我一般按“组织层、身份层、观测与安全层”拆三个模块每个模块一个独立目录内部按资源类型再拆文件。模块负责资源典型文件organizationOU、SCP、账号注册ou.tf、scp.tf、account-factory.tfidentity身份中心实例、权限集、账号分配sso.tf、assignment.tfobservability日志账户、S3 桶、CloudTrail、Configlogs.tf、audit.tf拆分的依据是生命周期。OU 和 SCP 变动频率低身份分配变动频率高日志规则随账号增长会不断追加。把它们混在一个目录里一次账号工厂扩容会牵动权限和日志文件review 的人很难判断意图。还要注意不要把一个环境的配置硬编码在模块里用var.environment传入后面测试才能同时跑多套环境而不互相干扰。3.3 托管 Landing Zone 的最小 Terraform 代码下面这段代码覆盖了组织声明、OU 创建、SCP 创建与附加。如果你的环境已经启用了 Control Tower组织资源建议改用data aws_organizations_organization读取现网避免和托管服务冲突。# versions.tf —— 锁定 provider 版本测试环境与生产环境保持一致 terraform { required_version 1.5 required_providers { aws { source hashicorp/aws version ~ 5.0 } } } # 组织与OU如果已启用 Control Tower把这里改成 data 源读取现网 resource aws_organizations_organization this { aws_service_access_principals [ controltower.amazonaws.com, sso.amazonaws.com, ] enabled_policy_types [SERVICE_CONTROL_POLICY] } resource aws_organizations_organizational_unit workloads { name Workloads parent_id aws_organizations_organization.this.roots[0].id } resource aws_organizations_organizational_unit security { name Security parent_id aws_organizations_organization.this.roots[0].id } # 一条示例SCP禁止删除审计追踪 resource aws_organizations_policy deny_cloudtrail_delete { name DenyCloudTrailDelete description 示例SCP禁止删除审计追踪 type SERVICE_CONTROL_POLICY content jsonencode({ Version 2012-10-17 Statement [ { Sid DenyCloudTrailDelete Effect Deny Action [ cloudtrail:DeleteTrail, cloudtrail:StopLogging ] Resource * } ] }) } # 把SCP附加到 Workloads OU resource aws_organizations_policy_attachment deny_cloudtrail_on_workloads { policy_id aws_organizations_policy.deny_cloudtrail_delete.id target_id aws_organizations_organizational_unit.workloads.id }aws_service_access_principals声明允许 Control Tower 和 SSO 服务访问组织这是后续自动化必须要做的。enabled_policy_types启用 SCP如果这个参数一开始没开后面挂策略会报错。SCP 的content用jsonencode生成避免手写 JSON 字符串的转义问题。注意CloudTrail:StopLogging也要禁止只禁止 DeleteTrail 拦不住攻击者先停日志再删事件。接下来是身份绑定。下面这段代码实现“每个目标账号自动绑定 PowerUser 权限集”。# sso.tf —— 每个账号进入 Landing Zone 后必须绑定一个默认权限集 data aws_ssoadmin_instances this {} resource aws_ssoadmin_permission_set power { name PowerUser instance_arn tolist(data.aws_ssoadmin_instances.this.arns)[0] session_duration PT8H } resource aws_ssoadmin_account_assignment power_assign { for_each toset(var.target_account_ids) instance_arn aws_ssoadmin_permission_set.power.instance_arn permission_set_arn aws_ssoadmin_permission_set.power.arn principal_id data.aws_identitystore_user.admin.user_id principal_type USER target_id each.value target_type AWS_ACCOUNT }data.aws_ssoadmin_instances读取身份中心实例 ARNfor_each遍历目标账号 ID 列表principal_id来自 identitystore 数据源。session_duration用 ISO8601 格式PT8H表示 8 小时。这段代码的意图是“每个新账号自动绑定权限集”账号工厂跑完后身份同步需要几分钟测试脚本要等待这个异步过程不要在 apply 后立刻断言。提示如果已启用 Control Tower不要试图用 Terraform 直接管理它已经占用的 OU 和 SCP先 import 进状态再用 lifecycle 声明哪些属性由平台托管。3.4 账号工厂把新账号批量接入的两种写法批量接入账号最常见的有两种做法。一种是 Terraform 内用aws_organizations_account声明一批账号适合测试和小规模交付。另一种是外部脚本调用aws organizations create-account批量创建再把返回的账号 ID 写回变量适合生产环境因为账号创建是异步的Terraform 状态和实际完成时间可能不同步。# account-factory.tf —— 账号清单驱动 locals { new_accounts { demo-shared { email demo-sharedexample.com, ou aws_organizations_organizational_unit.workloads.id } demo-prod { email demo-prodexample.com, ou aws_organizations_organizational_unit.workloads.id } demo-security { email demo-securityexample.com, ou aws_organizations_organizational_unit.security.id } } } resource aws_organizations_account this { for_each local.new_accounts name each.key email each.value.email parent_id each.value.ou }for_each的 key 就是账号名后面归属和标签都以它为索引。parent_id决定账号放进哪个 OU这一步直接决定了它受哪些 SCP 约束。注意邮箱只能用一次测试账号如果反复创建需要先关闭原账号再换新邮箱。真实环境中我不会用 Terraform 直接创建生产账号而是用脚本批量创建再导入状态因为create-account是异步的直接让 Terraform 管理容易出现“资源已创建但状态未更新”的中间态。4. 给 Landing Zone 做回归测试三层验证与最小命令集很多团队只做terraform plan就以为测试过了其实 plan 只能证明语法正确、云平台认可这次变更不能证明“身份能登录、日志能落桶、权限集生效”。回归测试要按成本从低到高分三层做。4.1 三层验证策略静态检查、漂移检测、行为验证静态检查负责在代码阶段拦截低级错误比如格式问题、语法错误、明显越权的策略。漂移检测负责发现真实环境与代码不一致比如有人手工改了 SCP 或日志桶策略。行为验证负责确认整条链路真的能跑通比如新账号能登录、日志对象出现在集中桶里。层级要发现什么执行时机常用工具静态检查语法错误、安全配置、越权策略每次提交terraform validate、tflint、checkov漂移检测真实环境与代码不一致、手工改动定时 / 每次 planterraform plan、AWS Config行为验证SSO 能登录、权限集生效、日志投递发版后 / 定期自写断言脚本三层不能互替。plan 看到 No changes 不代表行为正确行为验证通过不代表一年后不漂移。所以流水线里面三层顺序执行最后一层人工抽检。4.2 静态检查阶段terraform 与 checkov 的最小命令集# 1. 格式与语法检查 terraform fmt -check -recursive terraform validate # 2. 安全策略扫描把结果当作CI门禁 checkov -d . --framework terraform \ --skip-check CKV_AWS_272 \ --quiet # 3. 计划阶段输出为文件供下游断言 terraform plan -outtfplan.bin terraform show -json tfplan.bin tfplan.jsonterraform validate不需要初始化后端也能跑适合在 git 钩子里做快速反馈。checkov默认规则很严格第一次跑可能被大量告警吓到我会先人工评审后再用--skip-check排除那些明确接受风险的规则并把排除理由写进代码注释。terraform plan -out保存二进制计划后续必须用terraform show -json来解析计划 JSON 里包含每个资源的actions字段断言脚本可以直接判断是否有“替换”操作出现在不该出现的资源上。4.3 行为验证阶段用临时账号走通 SSO、预算与日志链路前置准备是创建一个临时测试账号然后轮询等待创建成功。# 行为验证脚本片段创建临时测试账号并等待可用 TMP_ACCOUNTdemo-test-$(date %s) aws organizations create-account --email tmp-${TMP_ACCOUNT}example.com \ --account-name $TMP_ACCOUNT # 轮询等待 CREATE_SUCCEEDED aws organizations list-accounts --query \ Accounts[?Name${TMP_ACCOUNT}].Status --output text账号创建是异步的轮询间隔建议 5 秒一次最长等 10 分钟。账号创建成功后还要等身份同步。这里邮箱必须每次不同否则create-account会直接报冲突。测试脚本跑完记得把临时账号关闭或移出避免占用邮箱额度。接下来是断言脚本。这份脚本把基线快照当作唯一事实来源本地和 CI 共用同一个文件。# verify_landing_zone.py —— 针对基线快照做断言 import boto3 import json baseline json.load(open(baseline/org.json)) org boto3.client(organizations) sso boto3.client(sso-admin) # 断言1所有 OU 都在预期路径里 roots org.list_roots()[Roots] ou_list org.list_organizational_units(ParentIdroots[0][Id]) actual_ous {ou[Name] for ou in ou_list[OrganizationalUnits]} expect_ous set(baseline[ous]) assert expect_ous actual_ous, f缺失 OU: {expect_ous - actual_ous} # 断言2每个生产账号都绑定了至少一个权限集 for acct in baseline[prod_accounts]: assignments sso.list_account_assignments( AccountIdacct, InstanceArnbaseline[sso_instance_arn], PermissionSetArnbaseline[power_permission_set_arn], ) assert assignments.get(AccountAssignments), f账号 {acct} 未绑定权限集list_account_assignments返回的AccountAssignments列表如果是空的说明权限绑定没生效不用去控制台人肉确认。prod_accounts列表来自baseline/org.json我把生产账号名单单独存文件临时测试账号自动被过滤避免误伤。4.4 把验证结果固化成断言清单行为验证的断言应该沉淀成一张清单每次发版后照着跑。我常用的一张表长这样验证项命令 / 方法预期结果组织结构与基线一致比较 list-ous 输出与基线 JSONOU 集合与基线相同账号归属正确遍历 list-parents账号父节点不在根下权限集绑定上述 python 断言每个生产账号至少一条记录日志到达集中桶s3api head-object 轮询5 分钟内对象存在预算告警生成测试账单收到事件通知多写一条断言之后排障时间就少一块。手工改了配置第二天定时任务跑漂移检测发通知这就是测试的长期价值。不要嫌脚本啰嗦这些断言是环境健康度的体温计。5. AWS Landing Zone 自动化与测试避坑手册从状态文件到最小权限下面的问题都是项目里反复出现的按“现象 → 原因 → 解决”写你可以直接对照日志特征排查。5.1 状态文件失同步、SSO 权限不生效与日志断流三个隐蔽场景坑一几周前还能正常跑的terraform apply这次一跑就报ConflictException或AlreadyExists定位到 Control Tower 托管的资源。最常见的原因是有人手工改了资源比如手动给某个 OU 加了 SCP或调整了日志桶策略导致真实环境和 Terraform 状态文件脱节。Landing Zone 平台服务还有自己的编排Terraform 不知道这些外部变更重放时两边打架。解决方法是先把这些资源terraform import进状态再看 plan 的 diff如果差异来自平台托管属性给对应资源加lifecycle { ignore_changes [...] }明确告诉 Terraform 哪些属性由平台代管并在代码注释里写明“此属性由平台接管禁止手工改动”。坑二新账号创建成功SSO 里也能看到账号但用户登录后角色权限还是旧版或者根本没有权限集。原因是aws_ssoadmin_account_assignment的传播是异步的控制台页面有时显示已分配但服务端还没完成。另一部分情况是权限集改了内联策略但没有重新触发 AccountAssignment 更新Terraform 看不出差异。解决方法是把list_account_assignments的轮询断言写进测试脚本等传播完成再往下走如果权限集是手工改的用aws sso-admin describe_permission_set和代码逐项对照。等待时间一般几分钟CI 里必须轮询判定不能固定 sleep 30 秒就完事。坑三新建子账号后CloudTrail 日志没有出现在集中 S3 桶里检查发现写入角色没有权限。最常见的原因是日志中心 S3 桶的 bucket policy 里只允许了之前那批账号新建账号不在白名单内。解决方法是账号工厂模块同时维护一个 bucket policy 变量每次新增账号就把账号 ID 追加进策略条件如果账号很多改用组织级条件键aws:PrincipalOrgID整个组织内的账号自动放行以后不用来回改策略。我一般直接上组织级条件省掉后续每次扩容都要改日志桶策略的负担。5.2 OU 共置与最小权限差异自动化测试的另外两个坑坑四测试脚本做“清理多余账号”时把生产环境里的账号一起删了或移走了。原因是测试账号和生产账号共用一个 Landing Zone测试脚本拿到的是完整账号列表没有按环境过滤。解决方法是给每个账号打强制标签Environment: prod|test所有自动化测试先按标签过滤更保险的做法是测试账号放在独立 OU并用单独的账号工厂流程管理。不要心疼那点成本这个隔离能挡掉最狠的一次事故。坑五同样一段 Terraform 代码本地apply成功一进 CI 流水线就报AccessDenied日志指向某个iam:*操作。原因是本地用的管理员角色流水线用 OIDC 或临时凭证最小权限策略没覆盖完全。另一个常见诱因是本地环境变量里残留了旧的AWS_PROFILE导致本地根本没用到预期的角色。解决方法是在流水线第一步强制打印当前身份并把 CI 角色的权限也写成 Terraform 模块和 Landing Zone 一起版本化。aws sts get-caller-identity这一条命令输出Account、Arn、UserId。看到 Arn 里的角色名和你预期不一致直接排查环境变量而不是花两小时看权限策略。我在所有自动化流程里都把这条命令放在最前面成本极低但能排除一大类“本地能跑、流水线不能跑”的玄学问题。6. 把自动化接进交付流程的最后一步本地闸门与变更影响表自动化代码写好了测试脚本也有了最后一步是把它装进团队的日常交付流程而不是放在某个人的电脑里。6.1 用 git pre-push 钩子做低成本回归在团队仓库里放一个共享钩子每次推送前先跑一遍静态检查挡掉最基础的格式和扫描问题。脚本写到.githooks/pre-push然后让每个开发者执行一次git config core.hooksPath .githooks。#!/usr/bin/env bash # .githooks/pre-push —— 每次推送前先过一遍静态检查 set -euo pipefail echo [pre-push] terraform fmt terraform fmt -check -recursive echo [pre-push] terraform validate terraform validate -no-color echo [pre-push] checkov scan checkov -d . --framework terraform --quiet-no-color是为了让输出在本地终端和 CI 里保持一致。set -euo pipefail保证任何一步失败就中断推送。这套钩子不能替代完整的 plan 和行为验证但能让同事不用等 CI 排队就发现问题。注意core.hooksPath指向的是目录而不是单个文件钩子文件要有可执行权限。提示core.hooksPath 配置只需要每个开发者执行一次钩子本身放进 git 仓库这样整个团队用的是同一份检查逻辑。6.2 变更影响表每次改动前先回答三个问题我不要求每个团队都上正式的变更管理工具一张表就够用。改任何 Landing Zone 相关代码前先回答三行内容这次改动涉及哪些资源会影响多少个账号有没有对应的行为验证脚本。回答不出来的变更不要进流水线。问题回答改的是 OU / SCP / 身份 / 日志哪一类资源例如新增一个 SCP 并附加到 Workloads OU影响哪些账号例如3 个生产账号需同步验证权限行为验证怎么做例如跑 verify_landing_zone.py 日志投递断言我自己吃过一次亏改了一个看起来只影响日志投递的变量结果把整个组织的 OU 路径带偏一批账号一夜之间脱离了 SCP 保护。从那以后凡是 Landing Zone 的改动我默认先跑一遍行为验证再提交。这个方向值不值得投入要看你的账号规模和管理频率但只要超过五个账号自动化与测试的投入一定会被审计和排障时间成倍补回来。希望帮到你。本文还有配套的精品资源点击获取
返回列表
PREV
查看更多资讯
NEXT
返回资讯列表