基于AWS多客户子账户的Terraform基础设施管理与CI流水线需求
解决方案:基于Terraform + AWS原生服务的多客户环境CI流水线搭建
嘿,针对你用Terraform管理多客户AWS子账户、搭建CI流水线复用模块的需求,我整理了一套完全贴合目标的落地方案,全程只用AWS服务,兼顾模块复用和客户环境独立性:
一、基础架构核心思路
- 用AWS Organizations统管所有客户子账户,主账户作为管理中枢,负责存储Terraform核心模块、调度CI流水线
- 每个客户子账户内拆分「开发/生产」环境,要么用Terraform工作区(Workspace)隔离,要么给每个环境单独配置状态文件,确保客户之间、环境之间完全独立
- 所有客户共享同一套Terraform核心模块,模块代码统一存在主账户的AWS CodeCommit仓库,避免重复造轮子
二、核心AWS服务选型(全AWS原生,无第三方工具)
- AWS CodeCommit:存两份代码——一份是Terraform核心模块,另一份是每个客户的环境配置文件(比如
customer-a-dev.tfvars) - AWS CodePipeline:搭建端到端的CI流水线,从模块变更触发到多环境验证部署全自动化
- AWS CodeBuild:作为流水线的执行引擎,专门跑
terraform init/plan/apply这些命令 - 跨账户IAM角色:让主账户的CI流水线能安全访问各个客户子账户的资源,不用硬编码密钥
- S3 + DynamoDB:存Terraform状态文件,DynamoDB用来做状态锁,防止多个流水线并发操作搞乱状态
三、模块变更触发的CI流水线完整流程
当核心Terraform模块更新时,流水线会自动按以下步骤走:
- 代码触发:CodeCommit检测到模块仓库的主分支变更,直接启动流水线
- 全客户开发环境预验证(Plan阶段)
- 遍历所有客户的开发环境配置
- 对每个客户,先通过
aws sts assume-role切换到对应子账户的IAM角色,再执行terraform init -upgrade拉取最新模块 - 运行
terraform plan -var-file=customer-x-dev.tfvars,生成变更计划并保存日志 - 只要有一个客户的Plan出错,流水线直接终止,立刻通知运维团队排查
- 批量部署开发环境(Apply阶段)
- 确认所有客户开发环境的Plan都没问题后,挨个执行
terraform apply -var-file=customer-x-dev.tfvars -auto-approve - 每个客户的Apply是独立的,某一个失败不会影响其他客户(你也可以改成“一个失败全停”,看团队风险偏好)
- 确认所有客户开发环境的Plan都没问题后,挨个执行
- 生产环境验证与部署(可选但推荐)
- 所有开发环境部署成功后,可以手动触发生产环境的Plan流程,或者设置延迟自动触发
- 生产环境的Plan结果必须人工审核,没问题再执行Apply,绝对不能直接自动部署
- 结果通知:用Amazon SNS发通知,把每个客户环境的执行日志链接附进去,方便团队跟进
四、关键实现细节
1. 多账户权限管控
- 在每个客户子账户里创建一个IAM角色,只允许主账户的CodeBuild服务角色来Assume它
- 角色权限要最小化,只给Terraform需要的资源操作权限(比如
ec2:CreateInstance、s3:PutObject),别给管理员权限 - 在CodeBuild的构建脚本里,用
aws sts assume-role拿临时凭证,切换到客户子账户再执行Terraform命令
2. 模块复用的版本控制
- 核心模块用语义化版本(比如
v1.0.0),客户配置里通过source = "git::https://git-codecommit.us-east-1.amazonaws.com/v1/repos/terraform-modules//ec2?ref=v1.0.0"指定版本 - 模块更新时,先打新版本标签,再通过CI流水线批量更新客户配置里的模块版本(或者手动更新,看团队习惯)
3. 状态文件隔离
- 每个客户的每个环境对应S3里的独立前缀,比如
s3://terraform-state-bucket/customer-a/dev/terraform.tfstate - DynamoDB锁表用
customer-a-dev作为锁ID,彻底避免不同环境的状态操作冲突
4. 核心构建脚本示例
# 切换到目标客户子账户 ASSUME_ROLE_OUTPUT=$(aws sts assume-role --role-arn arn:aws:iam::${CUSTOMER_ACCOUNT_ID}:role/terraform-ci-role --role-session-name terraform-ci) export AWS_ACCESS_KEY_ID=$(echo $ASSUME_ROLE_OUTPUT | jq -r '.Credentials.AccessKeyId') export AWS_SECRET_ACCESS_KEY=$(echo $ASSUME_ROLE_OUTPUT | jq -r '.Credentials.SecretAccessKey') export AWS_SESSION_TOKEN=$(echo $ASSUME_ROLE_OUTPUT | jq -r '.Credentials.SessionToken') # 初始化Terraform,指定对应环境的状态文件 terraform init -upgrade \ -backend-config="bucket=terraform-state-bucket" \ -backend-config="key=${CUSTOMER_ID}/${ENVIRONMENT}/terraform.tfstate" \ -backend-config="dynamodb_table=terraform-state-lock" # 生成变更计划 terraform plan -var-file=${CUSTOMER_ID}-${ENVIRONMENT}.tfvars -out=plan.tfplan # 执行部署(仅当Plan成功时) terraform apply -auto-approve plan.tfplan
五、额外优化建议
- 加AWS Config监控客户环境的资源合规性,确保模块变更后资源符合安全规范
- 用Amazon CloudWatch收集CI流水线和Terraform执行的日志,出问题了好排查
- 生产环境一定要加手动审批环节,哪怕自动化再成熟,也别跳过人工验证这一步
内容的提问来源于stack exchange,提问作者David Dusnoki
相关产品推荐
相关产品推荐

