terraform-provider-aws 实战:使用 EC2 Transit Gateway + RAM 实现跨账户 VPC Attachment
2026/9/17 2:28:34 网站建设 项目流程

terraform-provider-aws 实战:使用 EC2 Transit Gateway + RAM 实现跨账户 VPC Attachment

【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws

本指南基于 terraform-provider-aws 仓库中的官方示例 examples/transit-gateway-cross-account-vpc-attachment,完整讲解如何在两个 AWS 账户之间搭建 EC2 Transit Gateway:在账户 A 创建并共享 Transit Gateway,在账户 B 中挂载 VPC,再由账户 A 接受 Attachment。读完本文,你将掌握双 Provider 配置、RAM 资源共享、跨账户 Attachment 创建/接受以及其中的底层实现原理与限制。

示例解决的业务场景

在大型企业中,网络通常采用"中心化 + 分散"的架构:由中央网络团队在专用网络账户中统一创建 EC2 Transit Gateway,各业务账户通过 VPC Attachment 接入该网关,从而低成本地实现跨 VPC 互通。本例正是这一架构的最小可运行版本:

  1. 账户一(first):创建 Transit Gateway 与 RAM Resource Share,接受来自账户二的 VPC Attachment;
  2. 账户二(second):创建自己的 VPC / 子网,发起 VPC Attachment 请求。

仓库中还提供了两个同族示例可供对照参考:transit-gateway-cross-account-peering-attachment(跨账户 Peering)与 transit-gateway-intra-region-peering(区域内 Peering),它们共享同一套双 Provider 与 RAM 共享思路。

前置条件

运行本示例前,需要满足原文档明确列出的两项前提:

  • 两个 AWS 账户必须属于同一个 AWS Organizations 组织:Transit Gateway 的跨账户共享依赖组织的资源共享能力;
  • 必须启用 Resource Access Manager(RAM):只有 RAM 处于启用状态,才能将 Transit Gateway 作为资源共享给组织内其他账户。

此外,两个账户均需具备相应资源的创建权限(EC2、RAM、VPC),且运行环境已安装 Terraform(示例在 main.tf 中声明required_version = ">= 0.12")。

示例文件清单

文件作用
main.tf全部资源的声明:双 Provider、RAM 共享、VPC 与 Attachment
variables.tf声明 5 个输入变量(两个账户的密钥对 + 区域)
terraform.template.tfvars变量值的模板文件,含占位示例值
README.md运行说明与前置条件

变量设计:双账户凭据如何注入

variables.tf 中声明了 5 个无默认值的变量,意味着必须由使用者显式提供:

variable "aws_first_access_key" {} variable "aws_first_secret_key" {} variable "aws_second_access_key" {} variable "aws_second_secret_key" {} variable "aws_region" {}

对应 terraform.template.tfvars 中的占位值:

# First account aws_first_access_key = "AAAAAAAAAAAAAAAAAAA" aws_first_secret_key = "SuperSecretKeyForAccount1" # Second account aws_second_access_key = "BBBBBBBBBBBBBBBBBBB" aws_second_secret_key = "SuperSecretKeyForAccount2" aws_region = "us-east-1"

安全性提示:示例为保持简洁,直接在 Provider 中使用了access_key/secret_key。生产环境强烈建议改用 IAM Role 的跨账户 AssumeRole 或AWS_PROFILE环境变量,避免将长期凭据写入配置文件;terraform.tfvars应加入.gitignore

主配置逐段拆解

main.tf 是核心,下面按职责拆解。

1. 双 Provider:同一份配置管理两个账户

provider "aws" { alias = "first" region = var.aws_region access_key = var.aws_first_access_key secret_key = var.aws_first_secret_key } provider "aws" { alias = "second" region = var.aws_region access_key = var.aws_second_access_key secret_key = var.aws_second_secret_key }

两个 Provider 使用aliasfirst/second)区分,后续每个资源通过provider = aws.firstprovider = aws.second指定归属账户。这是 terraform-provider-aws 处理多账户的标准模式。

2. 数据源:探测可用区与账户 ID

data "aws_availability_zones" "available" { provider = aws.second state = "available" } data "aws_caller_identity" "second" { provider = aws.second }
  • aws_availability_zones:在账户二所在区域获取可用可用区列表,用于为子网挑选availability_zone
  • aws_caller_identity:返回账户二的account_id,它将被用作 RAM 共享的principal(即"共享给谁")。

3. 账户一:创建 Transit Gateway 与 RAM 资源共享

resource "aws_ec2_transit_gateway" "example" { provider = aws.first tags = { Name = "terraform-example" } } resource "aws_ram_resource_share" "example" { provider = aws.first name = "terraform-example" tags = { Name = "terraform-example" } }

aws_ec2_transit_gateway在账户一创建网关本体;aws_ram_resource_share创建 RAM 资源共享实体,作为后续关联资源与 principal 的容器。

4. 共享动作:把网关共享给账户二

# Share the transit gateway... resource "aws_ram_resource_association" "example" { provider = aws.first resource_arn = aws_ec2_transit_gateway.example.arn resource_share_arn = aws_ram_resource_share.example.id } # ...with the second account. resource "aws_ram_principal_association" "example" { provider = aws.first principal = data.aws_caller_identity.second.account_id resource_share_arn = aws_ram_resource_share.example.id }
  • aws_ram_resource_association:把 Transit Gateway 的 ARN 关联进 Resource Share,完成"共享什么资源";
  • aws_ram_principal_association:把账户二的account_id设为 principal,完成"共享给谁"。

这两个资源协同,RAM 才会把账户一的 Transit Gateway 授权给账户二。

5. 账户二:创建 VPC 与子网

resource "aws_vpc" "example" { provider = aws.second cidr_block = "10.0.0.0/16" tags = { Name = "terraform-example" } } resource "aws_subnet" "example" { provider = aws.second availability_zone = data.aws_availability_zones.available.names[0] cidr_block = "10.0.0.0/24" vpc_id = aws_vpc.example.id tags = { Name = "terraform-example" } }

账户二创建10.0.0.0/16的 VPC 与10.0.0.0/24的子网(取第一个可用区)。注意:TGW Attachment 要求每个可用区至少挂载一个子网,本例只使用单可用区以保持最小化。

6. 账户二:发起 VPC Attachment(Creator 侧)

# Create the VPC attachment in the second account... resource "aws_ec2_transit_gateway_vpc_attachment" "example" { provider = aws.second depends_on = [ aws_ram_principal_association.example, aws_ram_resource_association.example, ] subnet_ids = [aws_subnet.example.id] transit_gateway_id = aws_ec2_transit_gateway.example.id vpc_id = aws_vpc.example.id tags = { Name = "terraform-example" Side = "Creator" } }

这是本例最关键的编排点:账户二引用的是账户一创建的aws_ec2_transit_gateway.example.id,即"别人的网关"。跨账户操作存在先后依赖,因此必须通过depends_on显式声明等待两个 RAM 关联资源完成,否则会因资源共享尚未生效而创建失败。

7. 账户一:接受 Attachment(Accepter 侧)

# ...and accept it in the first account. resource "aws_ec2_transit_gateway_vpc_attachment_accepter" "example" { provider = aws.first transit_gateway_attachment_id = aws_ec2_transit_gateway_vpc_attachment.example.id tags = { Name = "terraform-example" Side = "Accepter" } }

账户二创建的 Attachment 初始处于pendingAcceptance状态,必须由**网关所属账户(账户一)**显式接受后才可用。aws_ec2_transit_gateway_vpc_attachment_accepter正是完成这一动作的专用资源,其transit_gateway_attachment_id直接引用账户二侧资源生成的 Attachment ID,Terraform 会据此自动推导跨账户的资源依赖顺序。

8. 资源创建顺序总览

整个 apply 的依赖图如下:

aws_ec2_transit_gateway (acc1) │ ├──> aws_ram_resource_share (acc1) │ ├──> aws_ram_resource_association (acc1) │ └──> aws_ram_principal_association (acc1) │ ├──> aws_vpc (acc2) ──> aws_subnet (acc2) │ └──> aws_ec2_transit_gateway_vpc_attachment (acc2,等待 RAM 完成后) └──> aws_ec2_transit_gateway_vpc_attachment_accepter (acc1)

运行示例

原文档提供了两种变量注入方式,任选其一:

方式一:复制模板文件(推荐)

cp terraform.template.tfvars terraform.tfvars # 编辑 terraform.tfvars,替换为真实的 Access Key / Secret Key / Region terraform init terraform apply

方式二:命令行直接传参

terraform apply \ -var="aws_first_access_key=AAAAAAAAAAAAAAAAAAA" \ -var="aws_first_secret_key=SuperSecretKeyForAccount1" \ -var="aws_second_access_key=BBBBBBBBBBBBBBBBBBB" \ -var="aws_second_secret_key=SuperSecretKeyForAccount2" \ -var="aws_region=us-east-1"

apply 成功后,账户二的 VPC 即通过 TGW 与账户一的网络平面打通(后续需配置路由表与传播才能真正转发流量)。需要销毁环境时执行terraform destroy(需带上同样的变量)。

源码视角:Attachment 资源的底层行为

Creator 侧资源参数与默认值

从 internal/service/ec2/transitgateway_vpc_attachment.go 的 Schema 可以看到aws_ec2_transit_gateway_vpc_attachment除示例用到的 3 个必填参数外,还支持以下可选参数:

参数类型默认值说明
appliance_mode_supportstringdisable是否启用 appliance 模式(面向设备负载均衡场景)
dns_supportstringenable是否启用 DNS 解析支持
ipv6_supportstringdisable是否启用 IPv6 支持
security_group_referencing_supportstring计算是否启用安全组引用支持
transit_gateway_default_route_table_associationbooltrue是否自动关联 TGW 默认路由表
transit_gateway_default_route_table_propagationbooltrue是否自动传播到 TGW 默认路由表

其中transit_gateway_idvpc_id均为ForceNew(见 源码第 90-101 行),即修改这两个属性会触发资源重建而非原地更新。

跨账户场景下的路由表限制(重要)

在 transitgateway_vpc_attachment.go 的 Create 实现 中有两处关键注释:

We cannot modify Transit Gateway Route Tables for Resource Access Manager shared Transit Gateways.

源码在创建 Attachment 后会先比较transitGateway.OwnerIdVpcOwnerId只有网关所有者与 VPC 所有者是同一账户时,才会处理默认路由表的关联(association)与传播(propagation);若两者不同(即本例的跨账户共享场景),则跳过默认路由表处理,以避免对共享 TGW 路由表产生越权修改。这正是跨账户场景中"共享方路由策略不受请求方控制"的实现体现。

Accepter 侧的真实 API 调用

transitgateway_vpc_attachment_accepter.go 的 Create 逻辑会调用 EC2 的AcceptTransitGatewayVpcAttachment接口,并以TransitGatewayAttachmentId为资源 ID 持久化状态,随后通过waitTransitGatewayVPCAttachmentAccepted等待 Attachment 进入available状态。该资源其余属性(dns_supportsubnet_idstransit_gateway_idvpc_idvpc_owner_id等)全部为Computed(见 Schema 第 38-93 行),即从云端读取回显,无需用户在配置中重复声明。

测试佐证

仓库在 internal/service/ec2/transitgateway_vpc_attachment_test.go 与 internal/service/ec2/transitgateway_vpc_attachment_accepter_test.go 中分别提供了_basic、跨账户(_cross_account相关用例)等 acceptance test,覆盖了 Creator 与 Accepter 双侧的创建、接受、状态等待与标签管理路径,可作为理解完整行为链的补充材料。

小结

通过本例可以总结出跨账户 TGW 集成的四个固定套路,可直接复用到你的生产网络架构中:

  1. 双 Provider alias隔离两个账户的凭据与区域;
  2. RAM 三件套aws_ram_resource_share+aws_ram_resource_association+aws_ram_principal_association)完成资源与授权对象的绑定;
  3. Creator 侧资源 +depends_on保证 RAM 共享生效后再发起 Attachment;
  4. Accepter 侧资源由网关所属账户显式接受,跨账户完成 Attachment 的最终可用。

理解这些资源在源码中的默认值与跨账户限制(尤其是共享 TGW 路由表不可修改的行为),能帮助你在设计组织级网络时避免踩坑,并进一步探索仓库中 transit-gateway-peering-attachment 等进阶示例。

【免费下载链接】terraform-provider-awsThe AWS Provider enables Terraform to manage AWS resources.项目地址: https://gitcode.com/GitHub_Trending/te/terraform-provider-aws

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询