Transit gateways that moved zero bytes in or out over the lookback window
What does ZopNight detect here?
ZopNight flags an AWS Transit Gateway when both its `BytesIn` and `BytesOut` metrics read exactly zero, on the average and the peak, with at least 7 days of coverage inside a 30-day window. Attachments bill by the hour regardless of traffic, so removing an unused gateway recovers its full priced cost. ZopNight ships this check switched off by default.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-164 |
| Category | idle |
| Severity | low |
| Metric | BytesIn, BytesOut |
| Threshold | 0 bytes in both directions |
| Evaluation window | 30d |
| Source | ZopNight |
| Permissions used | ec2:DescribeTransitGateways · ec2:DescribeTransitGatewayAttachments · cloudwatch:GetMetricStatistics |
Where it applies
Attachment hours accrue whether packets flow or not
Transit Gateway pricing has two parts: an hourly charge for each attachment and a per-GB data processing charge. The page’s worked example uses $0.05 per VPC attachment-hour and $0.02 per GB processed for one Region, and states that the VPC owner is billed for each hour a VPC is attached. The data charge falls to zero when traffic stops; the attachment charge does not.
A hub that was set up for a migration, a proof of concept or a network that has since been consolidated elsewhere can sit for months, billing every attachment by the hour.
Measuring traffic through a gateway
Transit Gateway publishes BytesIn and BytesOut in AWS/TransitGateway, and the
metrics reference
says Sum is the only meaningful statistic for both:
aws ec2 describe-transit-gateway-attachments \ --filters Name=transit-gateway-id,Values=tgw-0123456789abcdef0 \ --query 'TransitGatewayAttachments[].[TransitGatewayAttachmentId,ResourceType,ResourceId,State]'
aws cloudwatch get-metric-statistics \ --namespace AWS/TransitGateway --metric-name BytesIn \ --dimensions Name=TransitGateway,Value=tgw-0123456789abcdef0 \ --start-time 2026-08-26T00:00:00Z --end-time 2026-09-25T00:00:00Z \ --period 86400 --statistics SumRun the same query for BytesOut. Zero in both directions for a month means nothing crossed the
gateway.
Both directions must be flat
ZopNight needs both series. Each must have at least 7 days of coverage, and in each the average and the peak must be exactly zero. There is no small tolerance here: a single byte in either direction clears the gateway. The gateway must also carry a positive monthly cost in ZopNight’s cost data.
When a gateway is left alone
Missing either metric, or having less than 7 days of either, means ZopNight cannot prove the gateway is idle and says nothing. Gateways with no price, or a price of zero, are skipped rather than shown with a $0 saving. A gateway whose attachments are all VPN or Direct Connect is judged the same way, by bytes. ZopNight ships this finding switched off by default, so it may not appear in your account.
What removal recovers
saving = transit gateway monthly cost as priced in ZopNightcost after fix = 0Without billing data, ZopNight prices the gateway as one attachment-hour list rate times the hours it runs, about $36 a month at the $0.05 example rate, however many attachments it has.
Decommissioning an idle gateway
- Confirm no VPC, VPN or Direct Connect gateway still depends on it, including peering in other Regions.
- Remove route table associations and propagations.
- Delete each attachment, for example
aws ec2 delete-transit-gateway-vpc-attachment --transit-gateway-attachment-id. - Delete the gateway with
aws ec2 delete-transit-gateway --transit-gateway-id. - Update any CloudFormation or Terraform stacks that declare it.