Interface VPC endpoints paying per-AZ ENI fees for no traffic
What does ZopNight detect here?
An Interface endpoint bills an hourly fee for every ENI it places, 1 per subnet it spans, so a 3-AZ endpoint costs three times a single-AZ one before any byte moves. ZopNight fires only on endpoints whose BytesProcessed peak stays under 1 MiB across 30 covered days, and prices the saving per ENI.
Signal and threshold
| Field | Value |
|---|---|
| Rule IDs | RC-095 |
| Category | idle |
| Severity | low |
| Metric | none — pure configuration read |
| Source | vpc_endpoint_idle.go |
Where it applies
Gateway endpoints are free; this rule knows it
VPC endpoints come in two economics. Gateway endpoints (S3, DynamoDB) are free routing constructs. Flagging one is always wrong, and the rule hard-excludes anything discovery does not positively identify as an Interface endpoint. Interface (PrivateLink) endpoints are the billable kind: each one provisions an ENI per subnet, and each ENI carries an hourly fee plus data charges. The fee accrues identically at zero traffic, which is what makes an idle one worth hunting.
Multiplied by availability zones
The per-AZ structure is why these findings are bigger than they look. The standard three-subnet template creates three ENIs per endpoint (three hourly fees), and a VPC with a dozen service endpoints built that way carries dozens of billed ENIs. The rule reads the endpoint’s ENI count from discovery and prices cost as count × the single-AZ rate; an endpoint whose count was never captured abstains rather than assuming one.
What has to be true before it fires
Four gates, all mandatory: the endpoint is an available Interface endpoint; its BytesProcessed series exists with at least 30 days of coverage and a window peak under the 1 MiB floor (tolerating keepalive chatter while any real traffic spike disqualifies); the ENI count is known; and a positive per-ENI rate was resolved. Any gap abstains. This rule replaced an older fail-open version that flagged every available endpoint on no usage evidence at all. It also currently sits behind a deployment feature flag, so an eligible endpoint may not surface until that cohort gate opens.
Measure one endpoint yourself
aws cloudwatch get-metric-statistics \ --namespace AWS/PrivateLinkEndpoints --metric-name BytesProcessed \ --dimensions Name="VPC Endpoint Id",Value=vpce-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 MaximumDeleting without breaking DNS
Private DNS is the sharp edge: with the endpoint gone, the service hostname resolves back to public IPs, so security groups or route setups that assumed private paths may start failing closed. Confirm no application depends on the endpoint’s DNS names, delete from the VPC console, and each removed ENI stops billing immediately.