Idle Elastic IP: the monthly tax nobody invoices

Elastic IP addresses are free when they are doing their job: one address associated with one running EC2 instance or network interface. The moment that association breaks, AWS starts the meter. Unassociated addresses bill $0.005 per hour. Addresses on stopped instances bill the same rate. That is about $3.65 per address per month, every month, with no compute underneath it.

The line item is small enough that FinOps dashboards ignore it and large enough to accumulate. An account with 40 forgotten addresses after a platform migration pays roughly $146 per month for public IPs that route nowhere. Multiply that across dev, staging, and legacy sandboxes and the annual waste is real money with zero operational value.

The baseline math

AWS allows five Elastic IPs per region by default at no charge while associated with a running resource. Beyond that quota, or when an address is idle, the hourly charge applies in every region at the same $0.005 rate.

Ten idle addresses for a year: about $438. Fifty idle addresses: about $2,190. None of this shows up under EC2 compute. It sits under VPC or Elastic IP in Cost Explorer, often buried under data transfer and NAT unless you filter for it.

The four ways addresses go idle

1. Instance terminated, EIP kept for DNS cutover

The classic pattern. Ops keeps the Elastic IP during a migration window, updates DNS, and forgets to release the address. The instance is gone. The IP bills monthly until someone runs describe-addresses.

2. Stopped instances in non-prod

Dev teams stop instances overnight or over weekends to save compute but leave the Elastic IP attached. Stopped instances do not qualify for the free association. The IP charges while the instance sleeps.

3. Load balancer or NLB migration leftovers

Moving from a classic ELB to an ALB, or from EC2-based ingress to an NLB with static IPs, often leaves the old Elastic IPs allocated in the account. They are not in the Terraform state file for the new stack.

4. Autoscaling and blue-green teardown gaps

Blue-green deploy scripts allocate Elastic IPs for the green pool and release them on success. A failed rollback or aborted pipeline leaves the green addresses allocated with no running target.

The audit query

aws ec2 describe-addresses \
  --query 'Addresses[?AssociationId==null || InstanceId!=null].[PublicIp,InstanceId,AssociationId,NetworkInterfaceId]' \
  --output table

Filter for AssociationId null first. Those are unassociated and billing immediately. For the rest, cross-check InstanceId against describe-instances and flag any address on a stopped or terminated instance. Tag addresses with owner and expiry at allocation time. The release decision becomes obvious six months later.

The fix sequence

  1. Release unassociated addresses after confirming no DNS record still points at them.
  2. Disassociate and release IPs on long-stopped instances, or start the instance if you need the IP.
  3. Replace static Elastic IPs in dev with DNS names or ALB hostnames where possible.
  4. Add a monthly Config rule or Lambda check that alerts on unassociated addresses.

Use the calculator before the cleanup sprint

The free idle Elastic IP cost calculator totals hourly charges across unassociated and stopped-instance addresses so you can prioritize the cleanup. If the count is under ten, this is a fifteen-minute fix. If it is over fifty, schedule a region-by-region sweep and update the teardown runbook the same week.

AWS documents Elastic IP pricing on the Amazon VPC pricing page. The rate is consistent across standard regions; the calculator uses $0.005 per hour as the default.