# NAT Gateway High Outbound Traffic, Consider a Gateway Endpoint

> Explains why ZopNight stays silent on NAT-to-S3/DynamoDB traffic and how to size the gateway endpoint saving yourself.

Source: https://zop.dev/integrations/aws/recommendations/nat-gateway-high-outbound-traffic-consider-a-gateway-endpoint

---

## The lever: route S3 and DynamoDB around the NAT gateway

A NAT gateway bills per hour and per gigabyte processed. [VPC pricing](https://aws.amazon.com/vpc/pricing/)
says the data processing charge applies to every gigabyte through the gateway regardless of source
or destination, and its worked example for US East (Ohio) shows $0.045 per GB. The same page notes that
a gateway-type VPC endpoint for S3 avoids that charge, with no data processing or hourly fee for the
endpoint. [Gateway endpoints](https://docs.aws.amazon.com/vpc/latest/privatelink/gateway-endpoints.html)
exist for exactly two services, Amazon S3 and DynamoDB.

So a private subnet that reads objects from S3, ships logs to S3 or talks to DynamoDB
through a NAT gateway is paying a per-GB toll it does not need to pay.

## Why ZopNight does not raise this finding today

The saving is simple to state: S3 and DynamoDB bytes through the gateway, times the processing
rate. The first term is the problem. The NAT gateway's CloudWatch metric `BytesOutToDestination`
([NAT gateway metrics](https://docs.aws.amazon.com/vpc/latest/userguide/metrics-dimensions-nat-gateway.html))
counts all bytes leaving the gateway, with no breakdown by destination service. The split requires
VPC Flow Logs, which ZopNight does not collect.

Rather than publish a finding with a made-up or zero saving, ZopNight stays silent on this rule for
every NAT gateway. For a NAT gateway with no traffic at all, see
<a href="https://zop.dev/integrations/aws/recommendations/idle-nat-gateway">Idle NAT Gateway</a>, which ZopNight does price.

## Checking for missing gateway endpoints yourself

First, list the VPCs that already have gateway endpoints:

```bash
aws ec2 describe-vpc-endpoints --filters Name=vpc-endpoint-type,Values=Gateway \
  --query 'VpcEndpoints[].[VpcId,ServiceName,State]' --output table
```

Compare that with VPCs that route through a NAT gateway:

```bash
aws ec2 describe-nat-gateways --filter Name=state,Values=available \
  --query 'NatGateways[].[NatGatewayId,VpcId]' --output table
```

A VPC in the second list but missing `com.amazonaws.REGION.s3` or `com.amazonaws.REGION.dynamodb`
in the first is a candidate.

## Sizing the saving with Flow Logs

Enable a flow log on the NAT gateway's network interface with a custom format that includes
`pkt-dst-aws-service` and `bytes`. The [flow log record reference](https://docs.aws.amazon.com/vpc/latest/userguide/flow-log-records.html)
lists `S3` and `DYNAMODB` among the values of that field. Sum bytes where it equals either one over a
representative week, scale to a month and multiply by your Region's NAT processing rate.

```text
monthly saving = (S3 + DynamoDB bytes via NAT per month, in GB) x NAT processing rate per GB
```

## Adding a gateway endpoint

1. Create a gateway endpoint for S3 (and DynamoDB if used) in the VPC and associate it with the
   private subnets' route tables.
2. Check bucket policies that use `aws:SourceIp`. AWS notes that requests through the endpoint
   arrive from private VPC addresses, so those conditions must move to `aws:VpcSourceIp`.
3. Watch `BytesOutToDestination` on the NAT gateway drop over the following days.

**Note**
Prefix lists are specific to a Region, so traffic to S3 or DynamoDB in another Region does not use the endpoint.
