Uncover the Mystery of Your AWS IP Addresses

Use this Python/Boto3 script to automatically discover all private and public IP addresses across all AWS regions in your account. The script queries ENIs (Elastic Network Interfaces), extracts IP information, and exports results to a CSV file for easy analysis and documentation.
A Guide with Boto3
Get ready to embark on a thrilling journey of automation and discovery! I had the vision of creating a dynamic system that would effortlessly uncover all the private and public IP addresses in my environment. Not only that, but I also wanted to make this information accessible to my team through an internal website.
With Python as my tool of choice, I delved into the world of programming to bring my vision to life.
We'll start by obtaining all the ENIs, then use that information to uncover the private IP addresses associated with them. But we won't stop there, we'll also hunt down any public IP addresses linked to the ENIs.
And the adventure doesn't end there, we're taking it to the next level by conducting this search across all regions offered by AWS!
But wait, there's more! If you, like me, have multiple AWS profiles, we can add a cherry on top by allowing you to input the desired profile to run the query against. Get ready to conquer the world of IP addresses like never before!
Prerequisites
- AWS CLI (click here for CLI installations)
- AWS IAM programmatic credentials and necessary permissions
- Python (version 3 is recommended)
- PIP (version 3 is recommended)
- Boto (version 3 is recommended)
- IDE (I use PyCharm)
Your IAM credentials must have ec2:DescribeNetworkInterfaces and ec2:DescribeRegions permissions. If you have SCPs or permission boundaries restricting regional access, the script will gracefully handle errors and continue to the next region.
Code (with comments)
#Importing libraries: The first three lines of the code import the os, boto3, and csv libraries.
import os
import boto3
import csv
#Defining the function get_all_enis_with_ips: This function takes one argument, profile_name, which is the name of an AWS profile stored in the user's computer.
def get_all_enis_with_ips(profile_name):
os.environ['AWS_PROFILE'] = profile_name #Setting the AWS profile: The os.environ['AWS_PROFILE'] line sets the environment variable AWS_PROFILE to the value of profile_name.
client = boto3.client('ec2') #Creating a boto3 EC2 client: The line client = boto3.client('ec2') creates a boto3 client for Amazon Elastic Compute Cloud (EC2) using the default region.
ec2_regions = [region['RegionName'] for region in client.describe_regions()['Regions']] #Getting a list of EC2 regions: The line ec2_regions = [region['RegionName'] for region in client.describe_regions()['Regions']] gets a list of EC2 regions.
eni_info = {} #Initializing a dictionary for ENI information: The line eni_info = {} creates an empty dictionary eni_info to store information about ENIs.
for region in ec2_regions: #Creating a boto3 EC2 client for the region: The line client = boto3.client('ec2', region_name=region) creates a boto3 client for EC2 for the current region.
try: #Error handling: The code uses a try-except block to handle errors that may occur when calling the describe_network_interfaces method. If an error occurs (such as GuardRails or SCPs or other policies that deny regional access), the code prints an error message and continues to the next region.
client = boto3.client('ec2', region_name=region)
enis = client.describe_network_interfaces()['NetworkInterfaces'] #Getting ENI information: The line enis = client.describe_network_interfaces()['NetworkInterfaces'] uses the describe_network_interfaces method of the boto3 client to get information about all ENIs in the region.
eni_info[region] = []
for eni in enis: #Storing ENI information: The code uses a nested for loop to iterate through each ENI in the region. For each ENI, the code creates a dictionary eni_dict that contains information about the ENI's private IP addresses and public IP. The code appends this dictionary to a list of ENIs for the region, which is stored in the eni_info dictionary.
eni_dict = {}
eni_dict['PrivateIpAddresses'] = [private_ip['PrivateIpAddress'] for private_ip in
eni['PrivateIpAddresses']]
eni_dict['PublicIp'] = eni.get('Association', {}).get('PublicIp', '')
eni_info[region].append(eni_dict)
return eni_info
except Exception as e:
# If an error occurs, print the error message and continue to the next region
print("Error in region", region, ":", e)
continue
profile_name = input("Enter AWS profile name: ") #Getting the AWS profile name: The line profile_name = input("Enter AWS profile name: ") prompts the user to enter the name of an AWS profile.
eni_info = get_all_enis_with_ips(profile_name) #Getting ENI information: The line eni_info = get_all_enis_with_ips(profile_name) calls the get_all_enis_with_ips function, passing profile_name as an argument, to get information about ENIs.
with open('c:\\users\\arun.daniel\\eni_info.csv', 'w', newline='') as file: #Writing ENI information to a CSV file: The code uses a with statement to open a file named eni_info.csv in the specified
writer = csv.writer(file)
writer.writerow(['Region', 'Private IP Addresses', 'Public IP'])
for region, enis in eni_info.items():
for eni in enis:
writer.writerow([region, ','.join(eni['PrivateIpAddresses']), eni['PublicIp']])
Extend this script to include additional ENI metadata like attachment information, security groups, and tags. This data can help identify which resources own specific IP addresses and assist with security audits.
Code (Raw)
import os
import boto3
import csv
def get_all_enis_with_ips(profile_name):
os.environ['AWS_PROFILE'] = profile_name
client = boto3.client('ec2')
ec2_regions = [region['RegionName'] for region in client.describe_regions()['Regions']]
eni_info = {}
for region in ec2_regions:
try:
client = boto3.client('ec2', region_name=region)
enis = client.describe_network_interfaces()['NetworkInterfaces']
eni_info[region] = []
for eni in enis:
eni_dict = {}
eni_dict['PrivateIpAddresses'] = [private_ip['PrivateIpAddress'] for private_ip in
eni['PrivateIpAddresses']]
eni_dict['PublicIp'] = eni.get('Association', {}).get('PublicIp', '')
eni_info[region].append(eni_dict)
return eni_info
except Exception as e:
print("Error in region", region, ":", e)
continue
profile_name = input("Enter AWS profile name: ")
eni_info = get_all_enis_with_ips(profile_name)
with open('c:\\users\\arudani\\eni_info.csv', 'w', newline='') as file:
writer = csv.writer(file)
writer.writerow(['Region', 'Private IP Addresses', 'Public IP'])
for region, enis in eni_info.items():
for eni in enis:
writer.writerow([region, ','.join(eni['PrivateIpAddresses']), eni['PublicIp']])
Remember to update the output file path in the script to match your environment. The CSV output can be imported into Excel or integrated with inventory management tools for ongoing IP address tracking.
Troubleshooting
| Issue | Possible Cause | Solution |
|---|---|---|
| "ProfileNotFound" error | AWS profile name not configured or misspelled | Run aws configure list-profiles to see available profiles. Ensure the profile exists in ~/.aws/credentials or ~/.aws/config. |
| Empty CSV output | No ENIs exist in any region or permission issues | Verify you have ec2:DescribeNetworkInterfaces permission. Test manually with aws ec2 describe-network-interfaces. |
| "ModuleNotFoundError: No module named 'boto3'" | Boto3 not installed in Python environment | Install boto3 with pip install boto3 or pip3 install boto3. Ensure you're using the correct Python interpreter. |
| Script only returns data from one region | Bug in the original code - return statement inside loop | Move the return eni_info statement outside the for loop to iterate through all regions before returning. |
| Permission denied writing CSV file | File path doesn't exist or no write permissions | Ensure the directory exists and you have write permissions. Consider using a path in your home directory or current working directory. |