The AWS in-use public IPv4 address charge is the hourly fee for a public IPv4 address that is attached to a running resource. It shows up while the instance, load balancer, NAT gateway, or container task is doing useful work. Teams that already cleaned up idle Elastic IPs still pay it. The line they need in the Cost and Usage Report is PublicIPv4:InUseAddress, region-prefixed, for example USE1-PublicIPv4:InUseAddress.
PublicIPv4:IdleAddress is the other usage type. It covers allocated Elastic IPs that are not associated. Idle Elastic IP cleanup is the right article for that line. This one is the in-use hourly charge, including the auto-assigned public address on an EC2 instance you never allocated as an Elastic IP.
The list rate in commercial regions is $0.005 per public IPv4 address per hour. One address left attached runs about $3.60 across a 30-day month. A subnet full of instances that each received a public address at launch multiplies that quietly, because the charge does not wait for the address to sit idle.
What the hourly fee actually covers
AWS bills an in-use public IPv4 address when it is associated with an ENI, an Elastic IP in use, a NAT gateway, a Global Accelerator endpoint in some designs, an ECS task with a public IP, or another service-managed public address in the account. The bill does not care that the workload is "supposed" to be on the internet. Attachment is the meter.
Auto-assignment is the common surprise. A public subnet with MapPublicIpOnLaunch enabled gives every new instance a public IPv4 address. That address is in use for the life of the instance. Nobody allocated an Elastic IP, so the idle-IP report stays empty and the in-use line grows with the Auto Scaling group.
NAT gateways add a public address per AZ as part of the NAT itself. The NAT hourly and data-processing charges are a separate discussion in NAT gateway cost reduction. The PublicIPv4:InUseAddress quantity still increments once per NAT public address. Rightsizing NAT and removing idle EIPs will not zero this usage type while those addresses remain attached.
We pull the usage type from CUR, group by line_item_resource_id when AWS provides it, and fall back to an ENI inventory when the resource id is an allocation id or a network interface. The working list for engineering is: resource, address, attached or not, subnet public or private, and whether a public listener is a product requirement. Finance sees hours. Engineering sees which ENI to change.
Amazon documents address behavior in Instance addressing. The pricing page is where the hourly public IPv4 rate lives. We reconcile CUR to that rate so a region exception is visible instead of argued from memory.
Where the AWS in-use public IPv4 address charge comes from
The fix is an inventory, then a design choice per row. Some public addresses should stay. A public Application Load Balancer that serves customers has a reason to hold public IPv4 addresses, and the cost is a known unit cost of that entry point. We tag those as accepted and stop pretending a cleanup script should delete them.
The rest are accidents of subnet selection. Application instances in a public subnet, bastion hosts that exist because SSH was easier than Session Manager, and build runners with public IPs so they can reach the internet without a NAT path. Each of those can move.
The pattern we ship for the accidental rows:
- Instances run in private subnets with no public IPv4 assignment.
- Egress uses a path you already pay for on purpose, or VPC endpoints for AWS APIs so the instance does not need a public address of its own.
MapPublicIpOnLaunchis false on subnets that host those instances.- Launch templates set
AssociatePublicIpAddressto false so an ASG cannot opt back in. - Elastic IPs that were associated only to give an instance a stable public address are released after the private path works.
IPv6-only or dual-stack designs remove the IPv4 meter where the clients support it. We do not lead with a flag-day conversion of every subnet. We lead with the CUR line, the top ENIs, and a change that drops hours without taking the product offline.
A concrete check after the change: the next day's CUR filter on PublicIPv4:InUseAddress for that resource id goes to zero hours, and the instance still passes its health check through the private path. Hours are the evidence. A console screenshot of one subnet is not.
What we leave in place, and how the scorecard reads
Public load balancers, VPN endpoints you still require, and NAT gateways you have not yet replaced stay on the scorecard as accepted in-use addresses with an owner. The owner can see the hourly math. Accepted is different from invisible. When someone later asks why the line is not zero, the scorecard answers.
We also watch new accounts. An account vended from the organization landing zone should not default application subnets to public IPv4. The preventive control is the subnet setting and the launch template, checked by Config or by a small inventory job. A monthly surprise means the inventory is detective only and someone launched in the old subnet.
Rutagon's cost work here is a short audit of the usage type, a ranked list, and the infrastructure change for the rows you approve. We file the before-and-after hour counts in the GRC you already run when a control owner wants evidence that public addressing was reviewed. The primary audience is the person who owns the AWS bill.
Service-managed addresses need a service-specific action. Turning off MapPublicIpOnLaunch does nothing for a NAT gateway's address. The scorecard splits "our ENIs" from "service-managed" so a week is not lost in the wrong console. ECS services with assignPublicIp enabled are in the first bucket and are usually an easy win once the tasks can pull images through a private path.
A production lesson from the first pass
The first pass always finds a "temporary" public instance that is the only path to a private database. Removing the address without a replacement path is an outage, and the address comes back the same day. We sequence the work: VPC endpoints or a deliberate egress path first, then disable public assignment, then confirm the in-use hours drop. The AWS cloud infrastructure change is the path. The CUR line is how you know it worked.
We do not promise a percentage off the whole AWS bill. We promise a named usage type, an owner per remaining address, and a measured drop in hours for the addresses you chose to remove. That is the buyer outcome: the in-use public IPv4 line becomes a decision, not a residue of old subnet defaults.
Frequently Asked Questions
How is the in-use public IPv4 charge different from an idle Elastic IP?
Idle Elastic IPs bill under PublicIPv4:IdleAddress when an allocated address is not attached. The in-use charge bills under PublicIPv4:InUseAddress for addresses that are attached, including auto-assigned public IPv4 on a running instance. Cleaning up idle addresses leaves the in-use line untouched.
What is the commercial list rate?
AWS publishes $0.005 per public IPv4 address per hour in commercial regions. One attached address is roughly $3.60 over a 30-day month. Confirm the region on the pricing page, then reconcile CUR hours to that rate.
Which CUR usage type should finance filter on?
Filter line_item_usage_type for PublicIPv4:InUseAddress, including the region prefix on that usage type. IdleAddress is a separate family. Resource ids help engineering find the ENI, and some service-managed addresses need a second lookup.
Should every public address be removed?
No. A public load balancer that clients use is an accepted cost with an owner. Instances that received a public address because the subnet maps public IPs on launch are the usual removal. The scorecard separates accepted addresses from accidents.
How do you prove the change worked?
The resource's PublicIPv4:InUseAddress hours fall after public assignment is off and the workload still passes health checks on the private path. We keep that before-and-after with the change record. A subnet screenshot alone does not show the meter.
Talk to us about an AWS cost scorecard that starts from this usage type. Contact Rutagon at rutagon.com/contact, 907-841-8407, or contact@rutagon.com.