Transit Gateways attached but carrying zero bytes
What does ZopNight detect here?
A Transit Gateway bills roughly $36 a month for every attachment even when nothing crosses it. ZopNight reads BytesIn and BytesOut over 30 days and flags the gateway only when both directions sit at exact zero; one direction alone is never enough, and missing data means no finding.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-164 |
| Category | idle |
| Severity | low |
| Metric | none — pure configuration read |
| Source | transit_gw_idle.go |
Where it applies
Attachments are the bill, not the gateway
A Transit Gateway has no base charge of its own. AWS bills per attachment-hour, roughly $36 a month for each VPC, VPN or Direct Connect attachment, plus a per-GB processing fee on the traffic that crosses. So an abandoned TGW is not free: every attachment left in place keeps its own meter running, while the data-processing line reads zero precisely because nothing moves anymore.
The same pricing shape explains an edge case. A gateway with no attachments at all prices out to $0, and the rule drops it rather than recommend deleting something that already costs nothing. Whatever survives to become a finding is real, recoverable attachment spend.
Zero in both directions, or nothing
Two of the CloudWatch counters under AWS/TransitGateway carry the evidence: BytesIn and
BytesOut, each over a 30-day window. The gateway is idle only when the average and the
maximum of both series are exactly 0. A gateway that only egresses, or only ingresses, is
still doing a job and is never flagged. An earlier version of this check keyed on an
attachments=0 tag that no pipeline ever populated, leaving it permanently silent, and the
metric-based test replaced it.
Pulling BytesIn and BytesOut yourself
aws cloudwatch get-metric-statistics \ --namespace AWS/TransitGateway --metric-name BytesIn \ --dimensions Name=TransitGateway,Value=tgw-0123456789abcdef0 \ --start-time "$(date -u -v-30d +%Y-%m-%dT%H:%M:%SZ)" \ --end-time "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ --period 86400 --statistics Sum MaximumRun it a second time with --metric-name BytesOut. Both have to come back flat for the
finding to be valid.
Why some idle gateways still go unreported
The rule abstains whenever either byte series is absent or has less than a week of recorded coverage, whenever any sample is non-zero, and whenever no positive monthly price is on record. Beyond those data gates, emission currently sits behind a feature flag: findings stay held back until the aggregator fix this rule depends on is confirmed rolled out to stage. Severity is deliberately low: this is housekeeping, not a cost emergency.
Detaching before deleting
Removal is a guided workflow, not a one-shot delete. Confirm no VPC, VPN or Direct Connect gateway still terminates on the TGW, remove the remaining route-table associations, then delete the gateway itself. Any CloudFormation stack that references it needs updating too, or the next stack operation will fail on the resource you just removed, or quietly recreate it.