简介围绕 AWS Landing Zone 自动化与测试展开的实践资料集面向已具备一定 AWS 基础、需要落地多账户治理与合规基线的云架构师、运维及安全工程师。内容以 CloudFormation 模板、组织与 OU 管理脚本、SCP 策略样例、安全基线配置CloudTrail、Config、VPC Flow Logs、S3 桶策略为主线并配有测试环境搭建说明与校验脚本可用于搭建验证环境、演练账户创建与策略下发流程。压缩包共 69 个文件、约 1.85MB以 24 个 json 策略与配置、13 个 md 说明文档、11 个 yml 模板为主辅以 3 个 rb 校验脚本及 docx、pdf 参考材料目录按 cloudformation-tools、organizations、security、accounts 等模块划分便于分块查阅。已有 311 人学习。读者可据此理解 Landing Zone 的分层设计思路复用模板与策略快速搭建测试组织并借助校验脚本核对配置结果减少手工排查成本。1. 云上 Landing Zone 不是建完就完自动化与测试缺一不可云上 Landing Zone 自动化与测试最容易被做成“开通很漂亮、三个月后没人敢改”的工程。某团队脚本跑通就上线日志基线和策略绑定靠人记一次调整让测试环境先翻车。这份 landing-zone 资源包把代码示例、Python 测试和文档放在一起目标是基线可复现、可断言、可回滚。它解决账号交付慢、基线漂移、测试环境不可重复三类问题。策略模板、账号工厂脚本、Python 测试和文档各有边界先跑通测试目录再改模板比直接动生产组织单元稳得多。资源包的价值不在脚本数量而在把“改一条策略”变成可验证的固定动作。适合平台工程师、云安全同学、SRE 和写 Python 自动化的人。新手能跑通账号创建到策略断言的链路熟手重点看测试夹具、清理逻辑和参数化矩阵判断能否接进现有流水线。若正被账号交付和基线漂移困扰先拆测试目录再动模板翻车概率会低很多。2. 资源结构与运行环境先让 Python 测试跑在隔离账号里拿到这份资源包第一眼不要急着改账号工厂脚本。Landing Zone 的自动化代码和普通业务代码不一样它一动手就碰组织单元、策略绑定、日志归档和账号生命周期跑错一次可能把共享日志组或生产账号卷进去。我一般先看目录分层再把 Python 测试环境关进隔离账号最后跑一条冒烟命令确认策略解析和账号上下文都对得上。2.1 资源包分层策略、模板、脚本、测试各管什么资源包的分层思路很明确策略层管“允许什么、禁止什么”模板层管“资源长什么样”脚本层管“按什么顺序创建和绑定”测试层管“改完怎么证明没坏”文档层管“参数和边界写在哪”。这五层混在一起时最常见的结果是模板里塞了脚本逻辑测试又依赖人工点控制台最后没人敢删任何一行。分层不是为了好看而是为了出问题时能快速定位是哪一层漂了。策略层通常放服务控制策略、基线策略、标签策略和日志投递约束。它应该是可读的声明文件改一个条件就能在测试里断言而不是藏在某个脚本的字符串拼接里。模板层放账号基线、网络基线、日志桶和审计角色形状固定参数从外部传入。脚本层只做编排先查后建、绑定组织单元、挂策略、打标签、等状态收敛。测试层用 Python 读策略、调云 SDK、断言绑定关系。文档层写清参数含义和失败回退。目录职责放什么不该放什么排错时先看什么策略服务控制策略、基线策略、标签约束账号创建顺序、临时凭据策略条件是否命中测试组织单元模板账号基线、日志归档、审计角色人工审批流程、一次性脚本参数默认值是否被覆盖脚本账号工厂、策略绑定、清理大段业务逻辑、硬编码账号 ID幂等键和查询条件测试单元、契约、端到端断言生产凭据、共享资源删除夹具作用域和清理过滤条件文档参数表、运行顺序、回退步骤口头约定、聊天记录截图参数变更记录和边界说明这张表不是让你照着建目录而是用来判断资源包有没有把边界拆开。策略文件可以单独做单元测试模板可以单独做参数渲染脚本只在端到端测试里出现。测试目录先跑通再改模板最后才碰脚本里的账号创建逻辑顺序反了就容易把排错变成猜谜。2.2 本地环境与最小权限把云 SDK 调用关进沙箱本地环境我一般用虚拟环境加 pytest不把云 SDK 装进系统 Python。凭据只放环境变量或临时凭据文件测试账号单独开一个隔离组织单元权限只给账号创建、策略绑定、标签读写和只读查询。生产组织单元的凭据不要出现在本地环境里哪怕只是查一下账号列表。测试脚本一旦能碰生产清理逻辑写错就是事故不是返工。# 创建独立虚拟环境避免污染系统 Python python -m venv .venv source .venv/bin/activate # 安装测试依赖不锁死版本按资源包文档为准 pip install pytest pyyaml # 凭据走环境变量不写进代码块 export CLOUD_PROFILElanding-zone-test export CLOUD_REGIONregion-a这段命令只做三件事隔离 Python 环境、装测试依赖、把凭据入口指到测试 profile。CLOUD_PROFILE对应本地凭据文件里的测试账号配置CLOUD_REGION用占位区域代码实际跑的时候换成你所用云平台的区域标识。虚拟环境放在项目根目录下测试命令统一用python -m pytest避免不同机器上的 pytest 入口不一致。凭据不要写进 shell 历史临时文件用完删掉。# tests/conftest.py import os import pytest from cloud_sdk import Session # 替换成你所用云平台的 Python SDK 入口 pytest.fixture(scopesession) def cloud(): profile os.environ[CLOUD_PROFILE] region os.environ.get(CLOUD_REGION, region-a) # 只读加测试账号的最小权限凭据不碰生产组织单元 session Session(profile_nameprofile, region_nameregion) return session pytest.fixture(scopesession) def org(cloud): # 组织客户端单独封装测试里不直接拼底层请求 return cloud.client(org)这段夹具把云 SDK 会话限制在测试 profile 上scopesession表示整个测试会话复用一次连接避免每个用例重复鉴权。cloud.client(org)是资源包里的适配层写法底层换成你所用云平台的客户端构造方法即可。org夹具只暴露组织相关操作测试用例不直接拿底层 session 去调任意接口这样清理逻辑和权限边界都好收。注意测试账号的凭据只放环境变量或临时凭据文件别写进代码块也别和共享日志归档账号混用。2.3 第一轮冒烟一条命令确认策略解析与账号上下文环境好了不要直接跑全套端到端测试先跑冒烟。冒烟只做三件事读一遍策略文件能不能解析、当前凭据落在哪个账号、目标组织单元能不能查到。很多翻车不是策略写错而是凭据指到了另一个账号或者组织单元 ID 用了旧值。冒烟脚本把这三件事打印出来比看一堆报错快。# scripts/smoke.py import os import yaml from cloud_sdk import Session def load_policy(path): with open(path, r, encodingutf-8) as f: # 策略文件统一按 YAML 解析解析失败直接抛错 return yaml.safe_load(f) def main(): session Session( profile_nameos.environ[CLOUD_PROFILE], region_nameos.environ.get(CLOUD_REGION, region-a), ) org session.client(org) identity org.whoami() policy load_policy(policies/baseline.yaml) target_ou org.find_ou(os.environ.get(TARGET_OU, sandbox)) print(account_id:, identity[account_id]) print(policy_keys:, sorted(policy.keys())) print(ou_id:, target_ou[id] if target_ou else not-found) if __name__ __main__: main()脚本先构造测试会话再查当前身份、解析基线策略、查目标组织单元。TARGET_OU默认指向sandbox实际跑的时候用环境变量覆盖避免把生产组织单元写死在脚本里。policy_keys打印策略顶层键用来确认 YAML 结构没被缩进或合并键破坏。ou_id打印not-found时先查组织单元名称和父级关系不要急着改策略。# 先跑冒烟再跑测试 python scripts/smoke.py python -m pytest tests/ -q冒烟通过后再跑 pytest。-q只压输出不改变测试行为失败时去掉-q看完整断言。第一轮测试建议只跑单元和契约层端到端用例加-m not e2e跳过等冒烟里的账号上下文确认无误再放开。冒烟里account_id不是你预期的测试账号后面所有断言都不可信先修凭据再谈策略。3. 账号工厂自动化把基线配置拆成可幂等的步骤账号工厂是 Landing Zone 自动化里最容易写成“一次性脚本”的地方。控制台点一遍也能开通账号但下次加一个组织单元、改一条基线策略人工步骤就复现不出来。资源包用声明式模板加 Python 编排不是为了追技术潮流而是把“账号创建、组织单元绑定、策略挂载、标签写入”拆成可查询、可重试、可断言的步骤。纯脚本也能跑但没有幂等键和查询条件第二次跑就报资源已存在。3.1 为什么用声明式模板加 Python 编排而不是纯控制台纯控制台操作的问题是状态不可查。账号建在哪个组织单元、挂了哪条基线策略、标签是谁写的全靠人记。声明式模板把资源形状固定下来参数从外部传入模板本身不关心调用顺序。Python 编排负责查状态、补差异、等收敛遇到已存在的资源就跳过遇到半成品就修复。两者分开模板可以单独做渲染测试编排可以单独做幂等测试。纯脚本一把梭的问题是失败后不知道从哪继续。账号创建接口返回成功不代表账号已经可用策略绑定接口返回成功不代表策略已经生效。Python 编排里要加查询和等待不能只看创建接口的返回值。资源包里的脚本层一般会封装find_account、create_account、bind_policy、wait_until_ready这类适配方法底层换成你所用云平台的 SDK 对应方法测试只断言适配层输出不直接依赖底层请求形状。选型时还有一个现实约束账号工厂往往跨团队使用平台团队写脚本安全团队写策略业务团队填参数。模板加参数表能让三方看同一份声明Python 编排只做机械动作。把所有逻辑塞进一个脚本参数含义只能靠注释改错一个标签就可能让清理脚本误删共享资源。拆开之后参数表就是契约测试就是验收。3.2 账号工厂参数表组织单元、基线模板与幂等键参数表是账号工厂的合同。账号名、目标组织单元、邮箱别名、基线模板、标签、幂等键、超时时间每一项都要写清作用和改错后果。邮箱别名用保留域名避免测试账号误发到真实邮箱幂等键放在标签里重跑时先按名称和组织单元查查到就复用查不到才创建。超时时间不要拍脑袋账号创建和策略生效是两段等待分开设置。参数示例作用改错后果account_nametz-network-dev账号显示名也是查询键重名会导致复用错账号ou_idou-sandbox账号挂载的组织单元挂错会继承错误策略emailplatformtz-network-devexample.invalid账号通知邮箱用真实邮箱会收到测试邮件baselinebaseline-network基线模板名称模板不存在时账号裸奔tagsenvtest,ownerplatform清理和审计过滤条件缺 env 标签会被清理脚本跳过idempotency_keytz-network-dev-v1重跑时识别同一批次变更批次后复用旧键会误判timeout_seconds900等待账号可用的上限太短会误报失败太长会拖住流水线这张表里最容易忽略的是tags和idempotency_key。envtest不是装饰清理脚本靠它二次过滤owner用来定位责任人出问题能找到人。idempotency_key不要每次跑都生成新值同一个账号的同一轮变更复用同一个键变更批次时再换。timeout_seconds按账号创建和策略生效拆成两个等待更稳一个等账号状态一个等策略绑定结果。3.3 从账号创建到策略绑定一次改动的完整流程一次改动的流程我一般固定成六步改参数表、跑策略单元测试、渲染模板、在测试组织单元创建账号、绑定基线策略、跑端到端断言。步骤不能省尤其是渲染模板和策略单元测试它们能在调云接口之前拦掉大部分低级错误。创建账号和绑定策略分开跑失败时能判断是账号没准备好还是策略条件不匹配。改参数表只动目标账号的字段不同时改多个组织单元。跑策略单元测试确认 YAML 能解析、条件字段没有拼写错误。渲染模板检查组织单元、标签、基线名称是否落到最终配置。在测试组织单元创建账号先查后建记录返回的账号 ID。绑定基线策略等待绑定状态收敛再查一次绑定关系。跑端到端断言确认账号状态、组织单元归属、策略绑定和标签都对。# scripts/account_factory.py import os from cloud_sdk import Session def ensure_account(org, name, ou_id, tags): # 先按名称和组织单元查查到直接复用保证重跑不重复建号 found org.find_account(namename, parent_idou_id) if found: return found[id] # 邮箱用保留域名避免测试账号误发真实邮件 result org.create_account( namename, emailfplatform{name}example.invalid, parent_idou_id, role_nameOrgAccountAccessRole, tagstags, ) return result[account_id] def main(): session Session( profile_nameos.environ[CLOUD_PROFILE], region_nameos.environ.get(CLOUD_REGION, region-a), ) org session.client(org) account_id ensure_account( org, nameos.environ[ACCOUNT_NAME], ou_idos.environ[OU_ID], tags{env: test, owner: platform, baseline: baseline-network}, ) print(account_id:, account_id) if __name__ __main__: main()ensure_account先查后建查询键是账号名加组织单元避免同名账号跨组织单元误复用。role_name用通用占位名实际换成你所用云平台要求的角色名。tags里带env、owner、baseline清理和审计都靠这三个字段。example.invalid是保留域名测试邮箱不会真的投递。脚本只负责拿到账号 ID不在这里绑定策略职责分开更好排错。# scripts/bind_policy.py import os from cloud_sdk import Session def bind_baseline(policy_client, account_id, policy_name): # 先查已绑定策略已存在就跳过保证幂等 bound policy_client.list_bound_policies(target_idaccount_id) if any(p[name] policy_name for p in bound): return already-bound policy_client.bind_policy( target_idaccount_id, policy_namepolicy_name, enforceTrue, ) return bound def main(): session Session( profile_nameos.environ[CLOUD_PROFILE], region_nameos.environ.get(CLOUD_REGION, region-a), ) policy_client session.client(policy) state bind_baseline( policy_client, account_idos.environ[ACCOUNT_ID], policy_nameos.environ.get(BASELINE, baseline-network), ) print(state:, state) if __name__ __main__: main()绑定脚本先查已绑定策略存在就返回already-bound不存在才调用绑定。enforceTrue表示策略强制生效实际参数名按云平台 SDK 调整。target_id用账号 ID不要用账号名账号名可能被改。绑定完成后不要只看返回值端到端测试还要再查一次绑定关系确认策略真的挂上了。两次查询之间加等待避免接口最终一致性导致误判。4. 测试体系用 Python 写策略断言、回归和清理Landing Zone 的测试不能只做“脚本能跑”。策略断言要验证条件是否命中目标组织单元契约测试要验证云 SDK 适配层返回结构没变端到端测试要验证账号从创建到策略绑定整条链路。测试层用 Python 和 pytest 组织重点不是用例数量而是夹具作用域、参数化和清理逻辑。测试账号清理不干净第二次跑就报资源已存在最后测试环境变成垃圾场。4.1 测试分层单元、契约、端到端各测什么单元测试测策略解析和模板渲染不调云接口。喂一份策略 YAML断言条件字段、动作列表、资源范围符合预期喂一组参数断言模板渲染后的组织单元、标签、基线名称没有丢。契约测试测适配层用录制好的返回结构断言find_account、bind_policy、list_bound_policies的输出字段。端到端测试才调真实测试账号验证创建、绑定、查询、清理整条链路。测试层测什么是否调云接口失败先看什么单元策略解析、模板渲染、参数校验否YAML 缩进、必填参数、默认值契约适配层返回结构、错误码映射可用录制数据字段名、分页、空结果端到端账号创建、组织单元绑定、策略生效是仅测试账号凭据、组织单元 ID、等待时间清理测试账号回收、标签过滤是仅测试账号过滤条件、共享资源保护分层的好处是失败定位快。单元测试挂了改策略文件契约测试挂了改适配层端到端挂了先看凭据和组织单元再看等待时间。清理测试单独一层因为它最容易误删共享资源必须有标签二次过滤和共享资源白名单。测试分层不是形式端到端用例数量要少单元和契约用例可以多跑得快才能频繁回归。4.2 用 pytest 组织回归夹具、参数化与断言pytest 夹具我一般分三层cloud管会话org管组织客户端policy_resolver管策略查询。夹具作用域按需设置会话级复用连接函数级隔离测试账号。参数化用来覆盖不同组织单元的基线差异sandbox和prod用同一段断言期望策略不同。断言消息写清组织单元和策略名失败时不用翻代码就知道缺什么。# tests/test_landing_zone.py import pytest pytest.mark.parametrize(ou_name, expected_policy, [ (sandbox, baseline-sandbox), (prod, baseline-prod), ]) def test_ou_baseline(org, policy_resolver, ou_name, expected_policy): # 先查组织单元查不到直接失败避免后续断言误报 ou org.find_ou(ou_name) assert ou is not None, f组织单元 {ou_name} 不存在 # 查已绑定策略断言期望策略在列表里 bound policy_resolver.bound_policies(ou[id]) assert expected_policy in bound, ( f{ou_name} 缺少基线策略 {expected_policy}当前绑定{bound} ) pytest.mark.e2e def test_account_ready(org, account_factory): # 端到端只建一个测试账号标签必须带 envtest account account_factory.ensure( nametz-e2e-check, ou_namesandbox, tags{env: test, owner: platform}, ) assert account[status] ready, f账号未就绪{account} assert account[tags].get(env) test, 测试账号缺少 env 标签参数化把组织单元和期望策略绑在一起sandbox缺baseline-sandbox时断言消息直接指出当前绑定列表。test_account_ready标了e2e本地默认跑单元和契约流水线里再放开。account_factory.ensure内部先查后建测试用例不关心创建细节。断言账号状态和env标签状态没到ready就继续等不要用固定sleep硬拖。# 本地只跑单元和契约跳过端到端 python -m pytest tests/ -q -m not e2e # 流水线里跑全套失败保留最后一次输出 python -m pytest tests/ -q --tbshort-m not e2e用标记跳过端到端本地迭代快。--tbshort保留关键堆栈流水线日志不至于被长堆栈淹没。端到端失败时先看账号状态和标签再看策略绑定。测试账号名带统一前缀清理脚本按前缀加envtest双重过滤避免误伤共享账号。4.3 失败重试与清理别让测试账号变成垃圾场重试只加在“等待状态收敛”的地方不要给创建接口盲目重试。账号创建接口超时可能已经创建成功盲目重试会撞资源已存在。正确做法是先查后建查到就复用查不到再创建。策略绑定失败要区分“条件不匹配”和“接口临时失败”条件不匹配重试多少次都没用接口临时失败才加退避重试。清理脚本必须双重过滤账号名前缀加envtest标签共享日志组和审计角色一律跳过。# tests/cleanup.py def cleanup_test_accounts(org, prefixtz-): p a hrefhttps://download.csdn.net/download/weixin_42137723/18837301 stylecolor:#ec7500;font-size:14px; 本文还有配套的精品资源点击获取 /a img altmenu-r.4af5f7ec.gif srchttps://csdnimg.cn/release/wenkucmsfe/public/img/menu-r.4af5f7ec.gif stylewidth:16px;margin-left:4px;vertical-align:text-bottom;cursor:text; /p