This check flags Elastic IP addresses that AWS has allocated to your account but are not attached to any running resource. Idle EIPs cost money for no benefit, so either associate them with a resource or release them with aws ec2 release-address.
Elastic IPs are one of those AWS resources that quietly accumulate. You spin up an instance, allocate an EIP, tear the instance down later, and the address just sits there. AWS keeps charging you for it, and over months and across regions those charges add up to real money for absolutely nothing in return. This check catches those orphaned addresses before they become a line item nobody can explain.
What this check detects
The network_unusedpublicips check scans every region in your AWS account for Elastic IP addresses that are allocated but not associated with a network interface or EC2 instance. In AWS terms, that means the EIP has no AssociationId.
There are two common states that trigger the finding:
- An EIP that was allocated but never associated with anything.
- An EIP whose instance or network interface was terminated, leaving the address unattached.
Note: AWS gives you one free Elastic IP per running instance, as long as it stays associated. The moment an EIP is not associated with a running resource, AWS starts charging an hourly rate for it. This is intentional, since public IPv4 addresses are a finite resource and AWS wants to discourage hoarding.
Why it matters
The cost angle
As of the 2024 IPv4 pricing change, AWS charges for all public IPv4 addresses, including in-use ones, at roughly $0.005 per hour. Unassociated EIPs have always carried a charge. That works out to about $3.60 per address per month. One forgotten EIP is rounding-error territory. Fifty of them spread across a dozen regions and a handful of accounts is a few thousand dollars a year that delivers zero value.
Warning: Because EIPs are regional, idle addresses love to hide in regions your team rarely uses. A quick scan of us-east-1 will not catch the EIP someone left behind in ap-southeast-2 after a load test two years ago. Always check every region.
The security and operational angle
Cost is the obvious problem, but there is a subtler one. A pool of dangling Elastic IPs is a sign of incomplete teardown. If your automation does not release EIPs, it probably leaves other things behind too, like orphaned ENIs, security groups, and EBS volumes. Unattached EIPs are a useful canary for sloppy resource lifecycle management.
There is also a reuse concern. When you release an EIP, it goes back into the AWS pool and may be allocated to another customer. If you had DNS records, allowlists, or third-party integrations pointing at that address and you release it without cleaning those up, someone else can inherit traffic that was meant for you. That is a real subdomain-takeover-style risk for any EIP tied to a hostname.
How to fix it
Step 1: Find the unattached addresses
List every Elastic IP in a region and filter for the ones without an association ID:
aws ec2 describe-addresses \
--query "Addresses[?AssociationId==null].[PublicIp,AllocationId,Tags]" \
--output table
To sweep all regions in one go:
for region in $(aws ec2 describe-regions --query "Regions[].RegionName" --output text); do
echo "=== $region ==="
aws ec2 describe-addresses --region "$region" \
--query "Addresses[?AssociationId==null].[PublicIp,AllocationId]" \
--output text
done
Step 2: Decide associate or release
For each address, work out whether it is actually needed. If it is supposed to be attached to something, associate it. If nobody can explain why it exists, it is a candidate for release.
To associate an EIP with an instance:
aws ec2 associate-address \
--allocation-id eipalloc-0abc123def456789 \
--instance-id i-0123456789abcdef0
Step 3: Release what you do not need
Danger: Releasing an Elastic IP is irreversible. You cannot get the same address back, and it may be allocated to another AWS customer within minutes. Before you release, confirm there are no DNS records, firewall allowlists, or partner integrations pointing at the address.
aws ec2 release-address --allocation-id eipalloc-0abc123def456789
If you are working with EC2-Classic addresses (rare and legacy), you release by public IP instead:
aws ec2 release-address --public-ip 203.0.113.25
Tip: Before releasing in bulk, tag each candidate with a date and a reason, then wait a billing cycle. If nothing breaks and nobody complains, release them. A short quarantine period saves you from yanking an address that some forgotten cron job depends on.
How to prevent it from happening again
Manual cleanup is a treadmill. The goal is to make idle EIPs impossible to leave behind, or at least loud when they appear.
Manage EIPs in your IaC
If an Elastic IP is created by Terraform or CloudFormation and tied to the resource it serves, tearing down that resource releases the EIP automatically. The problem almost always starts with EIPs allocated by hand in the console.
resource "aws_eip" "nat" {
domain = "vpc"
tags = {
Name = "nat-gateway-eip"
ManagedBy = "terraform"
}
}
resource "aws_nat_gateway" "main" {
allocation_id = aws_eip.nat.id
subnet_id = aws_subnet.public.id
}
Tying the EIP to the NAT gateway means a terraform destroy cleans up both. No orphans.
Gate it in CI/CD with policy-as-code
You can use an AWS Config managed rule to continuously flag the problem. The eip-attached rule reports any EIP that is not associated:
aws configservice put-config-rule --config-rule '{
"ConfigRuleName": "eip-attached",
"Source": {
"Owner": "AWS",
"SourceIdentifier": "EIP_ATTACHED"
}
}'
Pair that with an EventBridge rule that fires when an EIP is released or allocated, so you have an audit trail of who created what.
Tip: Block manual EIP allocation entirely with an SCP or IAM policy in accounts that should only ever create infrastructure through pipelines. If a human cannot run allocate-address by hand, they cannot leave one behind by hand.
Schedule a sweep
For accounts where manual EIPs are unavoidable, run a scheduled Lambda that reports unattached addresses older than a threshold to Slack. Detection beats hoping someone remembers.
Best practices
- Tag every EIP at allocation time with an owner, environment, and purpose. An untagged EIP is a future mystery.
- Prefer IPv6 and private addressing where you can. Fewer public IPv4 addresses means fewer things to clean up and lower cost.
- Audit all regions, not just the busy ones. Idle resources hide in the quiet corners of your account.
- Clean up DNS and allowlists before releasing. A released EIP can be reassigned to a stranger, so make sure nothing points at it.
- Treat dangling EIPs as a process smell. If they keep appearing, your teardown automation has a gap worth fixing at the source.
Unattached Elastic IPs are cheap individually and easy to ignore, which is exactly why they pile up. Catch them with a continuous check, fix the few you find, and close the door so they stop coming back.

