Skip to main content
Cloud Cost Engineering

Data Transfer: The Silent Killer

Ravinder··5 min read
Cloud CostFinOpsAWSData TransferNetworkingNAT Gateway
Share:
Data Transfer: The Silent Killer

Data transfer is the tax AWS collects on every useful thing your system does. It does not appear on any infrastructure diagram. Nobody provisions it. It grows proportionally with your success — more users, more traffic, higher bill — and then keeps growing because architects assumed it was free. It is not free. At $0.09/GB out to the internet and $0.01/GB cross-AZ, it routinely accounts for 20–30 % of bills for data-intensive systems.

Anatomy of AWS Transfer Costs

Not all bytes are priced equally. The transfer cost hierarchy:

Traffic Type Price Notes
Internet egress (first 10 TB) $0.09/GB Per region; lower at higher tiers
Internet egress via CloudFront $0.0085–$0.085/GB Up to 6× cheaper
Cross-AZ (same region) $0.01/GB each way $0.02/GB round trip
Same-AZ Free Requires explicit AZ affinity
AWS to AWS (different region) $0.02/GB Even within same account
AWS PrivateLink / VPC Endpoint $0.01/GB Cheaper than NAT for S3/DynamoDB
S3 Transfer Acceleration +$0.04–$0.08/GB Additive to egress

The cross-AZ charge is the most surprising. At $0.02/GB round-trip, a service making 100 GB/day of cross-AZ calls pays $730/year per inter-service pair. At 50 service pairs in a microservices architecture, that is $36,500/year on internal traffic.

Finding Transfer Costs in CUR

-- All transfer line items, sorted by cost
SELECT
  line_item_usage_type,
  line_item_product_code,
  product_from_location,
  product_to_location,
  ROUND(SUM(line_item_usage_amount), 0)   AS gb_transferred,
  ROUND(SUM(line_item_unblended_cost), 2) AS cost_usd
FROM cur_db.cur_table
WHERE line_item_usage_start_date >= DATE_TRUNC('month', CURRENT_DATE)
  AND (
    line_item_usage_type LIKE '%DataTransfer%'
    OR line_item_usage_type LIKE '%Bytes%'
    OR line_item_usage_type LIKE '%NatGateway%'
  )
  AND line_item_unblended_cost > 0
GROUP BY 1, 2, 3, 4
ORDER BY cost_usd DESC
LIMIT 30;

Run this monthly. Any single usage type above $1,000 deserves investigation.

NAT Gateway: The Biggest Surprise

NAT Gateway charges $0.045/GB processed plus $0.045/hr per gateway. A busy NAT Gateway seeing 5 TB/month of traffic:

Processing: 5,000 GB × $0.045   = $225
Hourly:     730 hr × $0.045      = $32.85
Monthly total:                    $257.85

Multiply by the number of private subnets needing internet access. The solution is almost always S3 and DynamoDB Gateway Endpoints, which are free.

# Replace NAT Gateway traffic to S3 and DynamoDB with free Gateway Endpoints
resource "aws_vpc_endpoint" "s3" {
  vpc_id            = aws_vpc.main.id
  service_name      = "com.amazonaws.${var.region}.s3"
  vpc_endpoint_type = "Gateway"
  route_table_ids   = var.private_route_table_ids
 
  tags = {
    Name = "s3-gateway-endpoint"
    team = var.team
  }
}
 
resource "aws_vpc_endpoint" "dynamodb" {
  vpc_id            = aws_vpc.main.id
  service_name      = "com.amazonaws.${var.region}.dynamodb"
  vpc_endpoint_type = "Gateway"
  route_table_ids   = var.private_route_table_ids
 
  tags = {
    Name = "dynamodb-gateway-endpoint"
    team = var.team
  }
}

After deploying these, S3 and DynamoDB traffic routes through the endpoint rather than the NAT Gateway. The reduction in NAT Gateway data processing charges is typically 40–70 % for data-heavy workloads.

Cross-AZ Traffic Architecture

flowchart TD subgraph AZ_A["Availability Zone A"] A1[Service A pod] LB1[Load Balancer] A2[Service B pod] end subgraph AZ_B["Availability Zone B"] B1[Service A pod] B2[Service B pod] end A1 -->|Cross-AZ call 0.02/GB| B2 A1 -->|Same-AZ free| A2 LB1 -->|May route cross-AZ| B1 classDef expensive fill:#ff9999,stroke:#cc0000 classDef free fill:#99ff99,stroke:#009900 class A1,B2 expensive class A1,A2 free

Force same-AZ routing in Kubernetes with topology spread constraints:

# Deployment patch — prefer same-AZ routing
apiVersion: apps/v1
kind: Deployment
metadata:
  name: service-b
spec:
  template:
    spec:
      topologySpreadConstraints:
        - maxSkew: 1
          topologyKey: topology.kubernetes.io/zone
          whenUnsatisfiable: DoNotSchedule
          labelSelector:
            matchLabels:
              app: service-b

And for services in AWS Load Balancer Controller, enable AZ affinity:

apiVersion: v1
kind: Service
metadata:
  annotations:
    service.beta.kubernetes.io/aws-load-balancer-target-group-attributes: >
      target_group_health.dns_failover.minimum_healthy_targets.count=1,
      load_balancing.cross_zone.enabled=false

Internet Egress: CloudFront as a Cost Lever

Routing egress through CloudFront reduces transfer cost by up to 75 % and improves latency. The math on 50 TB/month:

Direct egress:     50,000 GB × $0.09   = $4,500
Via CloudFront:    50,000 GB × $0.021* = $1,050
Monthly saving:                          $3,450
Annual saving:                           $41,400

*Blended rate across tiers for US/EU traffic.

resource "aws_cloudfront_distribution" "api" {
  enabled = true
 
  origin {
    domain_name = aws_lb.api.dns_name
    origin_id   = "api-alb"
 
    custom_origin_config {
      http_port              = 80
      https_port             = 443
      origin_protocol_policy = "https-only"
      origin_ssl_protocols   = ["TLSv1.2"]
    }
  }
 
  default_cache_behavior {
    target_origin_id       = "api-alb"
    viewer_protocol_policy = "redirect-to-https"
    allowed_methods        = ["DELETE", "GET", "HEAD", "OPTIONS", "PATCH", "POST", "PUT"]
    cached_methods         = ["GET", "HEAD"]
    compress               = true
 
    forwarded_values {
      query_string = true
      cookies { forward = "none" }
    }
 
    min_ttl     = 0
    default_ttl = 0   # pass-through for API; cache at application level
    max_ttl     = 86400
  }
 
  price_class = "PriceClass_100"  # US, Canada, Europe only — cheapest tier
}

Transfer Cost Reduction Checklist

flowchart LR A[Audit Transfer Costs] --> B{S3/DynamoDB via NAT?} B -->|Yes| C[Add Gateway Endpoints] A --> D{Cross-AZ microservice calls?} D -->|Yes| E[Topology spread + AZ-aware LB] A --> F{High internet egress?} F -->|Yes| G[Route via CloudFront] A --> H{Inter-region traffic?} H -->|Yes| I[Evaluate data residency / replication strategy] C --> J[Measure NAT GW cost reduction] E --> J G --> J I --> J

Key Takeaways

  • Cross-AZ traffic at $0.02/GB round-trip is invisible in architecture diagrams but appears prominently in the bill; audit it before designing microservice communication patterns.
  • S3 and DynamoDB Gateway Endpoints are free and eliminate the largest category of NAT Gateway processing charges — this is always the first NAT Gateway optimization to make.
  • CloudFront is not just a CDN; it is an egress cost reduction mechanism that cuts internet transfer costs by 50–75 % while improving global latency.
  • The NAT Gateway hourly charge is secondary to the per-GB processing charge; reducing data volume through the gateway matters more than reducing the number of gateways.
  • Kubernetes topology spread constraints and AZ-aware load balancing are the implementation levers for cross-AZ cost reduction in container workloads.
  • Build transfer cost into capacity planning — every architectural decision that increases data movement has a per-byte cost that compounds with scale.
Share: