TGW:Subnet 路由与 ping 排障
验证:静态检查 · 核验于 2026-10-14
- 适用版本
- AWS API 配置只读核对;本文示例命令未重新执行
- 验证范围
- 案例基于只读云配置检查;初次故障恢复由操作者确认,反向 ping 案例未代修或复测。文档构建、链接与 Bash 语法本地检查。
Ping 排障同时查三层:subnet/TGW 路由、两端 Security Group、NACL。 Attachment available 或正向 ping 成功,都不代表反向主动请求已获准。默认 NAT / Internet Gateway 路由也不能代替对端 VPC → TGW 路由。
最小双向路由#
示例:A=172.31.0.0/16,B=10.230.0.0/16,两者连接同一 TGW;EC2 A=172.31.1.10,EC2 B=10.230.1.20。地址和资源名称均为示意。
| 检查位置 | 请求 / 回程所需路径 |
|---|---|
| A 业务 subnet 的 route table | 10.230.0.0/16 → TGW |
| A attachment 关联的 TGW route table | 10.230.0.0/16 → B attachment |
| B 业务 subnet 的 route table | 172.31.0.0/16 → TGW |
| B attachment 关联的 TGW route table | 172.31.0.0/16 → A attachment |
| 两端 attachment subnet 的 route table | 能到达本 VPC 的业务地址;普通直连场景由 local 路由提供 |
这里展示按整个 VPC 网段互联;仅连接指定 subnet / 主机时,可按需要使用更精确的前缀,并相应限制 SG。
默认 propagation 只维护 TGW 表,不向 VPC subnet 表添加路由。 查 subnet 是否显式关联 route table;没有显式关联时使用该 VPC 的 main route table。
Attachment subnet 和业务 subnet#
- 每个启用的 AZ 选择一个 attachment subnet,供 TGW 放置网络接口;同 AZ 的其他业务 subnet 可经该入口访问 TGW。
- 无须把每个业务 subnet 都选进 attachment。业务所用 AZ 应有接入;两端 EC2 无须位于同一 AZ。
- 可以采用独立 attachment subnets;它们与业务 subnet 的路由分别核对,尤其是插入 NAT / firewall 的架构。
- 跨账号按 AZ ID 比较实际位置,不能只比较
ap-northeast-1a这样的账号侧名称。
Security Group:按发起方向检查#
检查承载通信的 ENI 实际关联的全部 SG,核对 Group ID、协议、来源/目的。两边都叫 default 不代表同一个 SG;source 引用自身 SG 仅允许带该 SG 的来源,不自动允许另一个 VPC 的同名组。多个 SG 的 Allow 规则合并生效。
沿用上方 A / B 的示例 IP,分别检查:
| 谁主动发起 ping | 发起方 Outbound | 接收方 Inbound |
|---|---|---|
| A → B | A 允许 ICMP 到 10.230.1.20/32 |
B 允许来源 172.31.1.10/32 的 Echo Request |
| B → A | B 允许 ICMP 到 172.31.1.10/32 |
A 允许来源 10.230.1.20/32 的 Echo Request |
已有 All traffic egress 时无需重复添加。Inbound 可用 Custom ICMP – IPv4 / Echo Request(type 8、code 0);开放 TCP 0–65535 不包含 ICMP。
SG 有状态:允许请求后,Echo Reply 自动放行,不需要为回包再加反向 SG 规则。反向主动 ping 是新的 Echo Request,必须按表中另一行检查。 NACL 无状态,仍需放行请求和回复。ICMP 规则、SG 规则与引用、stateful 行为
若用对端 SG ID 代替 CIDR 授权,须在 TGW 和相关 VPC attachments 启用 Security Group Referencing support;TGW 场景仅支持 Inbound 引用,跨 TGW Peering 不支持。支持条件
案例:A ping B 通,B ping A 不通#
只读检查发现:路由、attachment AZ 和 NACL 已符合要求;B 的 SG 允许 ICMP,A 的 Inbound 只引用自己的 sg-a,而 B 关联的是另一个 sg-b。
- A → B 成功:A 可以出站,B 允许请求,A 自动接收响应。
- B → A 失败:A 没有允许 B 的新请求。修复方向是在 A 的 SG Inbound 放行来源 B 的 Echo Request;仅这两台主机测试可限定
10.230.1.20/32,无需扩大为所有来源、所有协议。
此案例只读确认了配置阻断点,未代执行修改或登录实例验证 OS firewall。
案例:TGW 路由正常,但 ping 不通#
一次东京 Region 的只读排查中,两台 EC2 均 running、状态检查正常,位于不同 AZ;attachment 覆盖正确,TGW 已有双方 active propagated routes,NACL 放行。实际发现:
| 阻断点 | 当时的配置 | 修复要点 |
|---|---|---|
| 请求没进入 TGW | A subnet 只有 local 和 0.0.0.0/0 → NAT |
对端 B 网段 → TGW |
| 回包走错方向 | B subnet 只有 local 和 0.0.0.0/0 → IGW,另有无关的 S3 Endpoint 路由 |
对端 A 网段 → TGW |
| ping 协议未放行 | B 的 SG 只允许 TCP 0–65535 |
允许来源 A 的 ICMP IPv4 Echo Request |
具体 SG 规则按上方 发起方向检查表核对。
检查后操作者调整配置并确认 ping 恢复。排查期间没有执行云端变更或登录实例;OS firewall / 禁止响应 ICMP 的设置不在当次只读检查范围内。
按顺序定位#
- 实例:确认实际私有 IP、VPC、subnet、AZ、running 状态。
- VPC routes:按目的 IP 匹配源 subnet 路由,再检查回程;检查是否误走默认 NAT/IGW。
- TGW:attachment 状态/AZ、实际 association、双方目的路由、blackhole。 若关联的是 Policy Table,先检查规则是否匹配、选择了哪张 Route Table;无匹配会丢包。
- Security Group:查实际 ENI 的全部 SG;按本次发起方向核对 source egress / destination ingress,不能把响应获准当成反向主动请求获准。
- NACL:核对业务及 attachment subnet,按规则顺序检查请求和回复。
- 主机与应用:网络配置正确后,再由有权操作者查 OS firewall、监听地址和真实服务端口。
ping 成功只验证 ICMP;HTTPS 还需监听、TCP 443、TLS 和应用授权。DNS 失败时单独检查 Route 53 解析路径。
只读检查命令(不创建 Reachability Analyzer 或 SSM 任务)
本机 Bash,已有 AWS CLI profile;变量替换为实际值。以下仅查询,不执行资源增删改或远程命令。每阶段根据输出填写下一阶段的 ID,不默认选列表第一项。
PROFILE='REPLACE_PROFILE'
REGION='ap-northeast-1'
SOURCE_INSTANCE='REPLACE_SOURCE_INSTANCE_ID'
TARGET_INSTANCE='REPLACE_TARGET_INSTANCE_ID'
AWS_ARGS=(--profile "$PROFILE" --region "$REGION" --no-cli-pager)
aws sts get-caller-identity "${AWS_ARGS[@]}"
aws ec2 describe-instances "${AWS_ARGS[@]}" \
--instance-ids "$SOURCE_INSTANCE" "$TARGET_INSTANCE" \
--query 'Reservations[].Instances[].{Id:InstanceId,State:State.Name,Vpc:VpcId,Subnet:SubnetId,IP:PrivateIpAddress,AZ:Placement.AvailabilityZone,SG:SecurityGroups,ENIs:NetworkInterfaces[].{Id:NetworkInterfaceId,IP:PrivateIpAddress,SG:Groups}}'从上方输出填入两端 VPC、subnet、SG,检查每张表的 Associations:
SOURCE_VPC='REPLACE_SOURCE_VPC_ID'
TARGET_VPC='REPLACE_TARGET_VPC_ID'
SOURCE_SUBNET='REPLACE_SOURCE_SUBNET_ID'
TARGET_SUBNET='REPLACE_TARGET_SUBNET_ID'
# 有多个 SG 时,把每个 ID 作为一个数组元素列出。
SOURCE_SGS=('REPLACE_SOURCE_SECURITY_GROUP_ID')
TARGET_SGS=('REPLACE_TARGET_SECURITY_GROUP_ID')
aws ec2 describe-vpcs "${AWS_ARGS[@]}" \
--vpc-ids "$SOURCE_VPC" "$TARGET_VPC"
aws ec2 describe-route-tables "${AWS_ARGS[@]}" \
--filters "Name=vpc-id,Values=$SOURCE_VPC,$TARGET_VPC"
aws ec2 describe-transit-gateway-vpc-attachments "${AWS_ARGS[@]}" \
--filters "Name=vpc-id,Values=$SOURCE_VPC,$TARGET_VPC"
aws ec2 describe-subnets "${AWS_ARGS[@]}" \
--filters "Name=vpc-id,Values=$SOURCE_VPC,$TARGET_VPC" \
--query 'Subnets[].{Id:SubnetId,AZ:AvailabilityZone,AZId:AvailabilityZoneId,CIDR:CidrBlock}'
aws ec2 describe-security-groups "${AWS_ARGS[@]}" \
--group-ids "${SOURCE_SGS[@]}" "${TARGET_SGS[@]}" \
--query 'SecurityGroups[].{Id:GroupId,Name:GroupName,Vpc:VpcId,Inbound:IpPermissions,Outbound:IpPermissionsEgress}'
aws ec2 describe-network-acls "${AWS_ARGS[@]}" \
--filters "Name=association.subnet-id,Values=$SOURCE_SUBNET,$TARGET_SUBNET"SG 输出中 IpProtocol=-1 表示所有协议,tcp 不包含 ICMP;ICMP 规则里的 FromPort/ToPort 表示 type/code。UserIdGroupPairs 是引用的 SG,IpRanges 是允许的 CIDR。attachment 使用独立 subnet 时也检查其 NACL。随后查询 TGW 的真实关联表:
TGW='REPLACE_TGW_ID'
aws ec2 describe-transit-gateway-attachments "${AWS_ARGS[@]}" \
--filters "Name=transit-gateway-id,Values=$TGW"
aws ec2 describe-transit-gateway-route-tables "${AWS_ARGS[@]}" \
--filters "Name=transit-gateway-id,Values=$TGW"
# 从 attachment 的 Association 取得 table ID;两端不同表时分别查询。
TGW_TABLE='REPLACE_ASSOCIATED_TGW_ROUTE_TABLE_ID'
aws ec2 get-transit-gateway-route-table-propagations "${AWS_ARGS[@]}" \
--transit-gateway-route-table-id "$TGW_TABLE"
aws ec2 search-transit-gateway-routes "${AWS_ARGS[@]}" \
--transit-gateway-route-table-id "$TGW_TABLE" \
--filters Name=state,Values=active,blackhole \
--max-results 1000若 AdditionalRoutesAvailable=true,按目标 CIDR 缩小搜索后继续核对,不能把首批结果当成完整路由表。VPC route table 的 TGW target 是 tgw-*;TGW table 的下一跳是 tgw-attach-*。