How do I identify, monitor, and optimize my VPC public IPv4 usage?

7 minute read
3

I want to identify, monitor, and optimize my Amazon Virtual Private Cloud (Amazon VPC) IPv4 usage.

Resolution

Note: Effective February 1, 2024, all public IPv4 addresses incur a charge of $0.005 per IP address per hour whether attached to a service or not. If you're an AWS Free Tier customer for Amazon Elastic Compute Cloud (Amazon EC2), then you receive 750 free hours of usage. This free usage is for when you launch an Amazon EC2 instance with a public IPv4 address.

To identify, monitor, and optimize your IPv4 usage, complete the following:

Turn on your Public IP Insights

Use Public IP Insights to show you any public IPv4 addresses that are currently in use by services across AWS Regions at no cost. Use Public IP Insights to monitor, analyze, and audit your public IPv4 addresses usage.

To view public IP insights, create an IPAM pool under Free Tier. Also, after you set up Public IP Insights, you can access it from the Amazon VPC IP Address Manager.

Note: After you create an IPAM pool, it might take time before Public IP Insights shows reports that are related to your public IPv4 addresses.

Turn on your Cost and Usage Report

Your AWS Cost and Usage Report (CUR) includes usage data related to public IPv4 address that are in use or not in use. When you create your CUR, you can select Include Resource IDs to get more detailed resource-level analysis. After you create your CUR, AWS updates the report files that contain data for the month to date at least once a day. This allows you to analyze historical IPv4 usage data. Also, you can access the reports from an Amazon Simple Storage Service (Amazon S3) bucket.

Note: It can take up to 24 hours for AWS to deliver reports to your Amazon S3 bucket.

Identify Public IPv4 addresses immediately

Note: It's a best practice to use CUR and Public IP Insights for your planned analysis of public IPv4 address usage.

To immediately identify services that use public IPv4 addresses, use either the AWS Management Console or the AWS CLI.

AWS Management Console

To analyze your network interfaces to check the services that consume public IPv4 addresses, complete the following steps:

  1. Open the Amazon EC2 console, and then select Network Interfaces.
  2. Use the filter to select Public IPv4 Addresses. Enter <*> for the value. This filter identifies all the elastic network interfaces that use the primary public IPv4 address.
  3. Use the elastic network interface description and interface type to identify the service that uses the public IPv4 address.
  4. To show all public and secondary IP addresses that have elastic network interfaces in a Region, run the following command:
    Note: Replace example-region with the required Region.
    aws ec2 describe-network-interfaces --region example-region --query 'NetworkInterfaces[*].PrivateIpAddresses[?Association.PublicIp].Association.PublicIp[]' --output table

For public IPv4 addresses that are used by the Site-to-Site VPN, see How do I check the current status of my VPN tunnel?

For public IPv4 addresses that are used by standard and custom Global Accelerator, see Viewing your accelerators.

To View idle or associated Elastic IP addresses, complete the following steps:

  1. Open the Amazon EC2 console.
  2. In the navigation pane, choose Network & Security, and then choose Elastic IPs to view Elastic IP addresses.
  3. To view resources that use an Elastic IP address, first select the Elastic IP address. Then, check the network interface or instance field for more information.

Note: BYOIPs aren't charged. AWS Global Accelerators are billed in us-west-2.

AWS CLI

Note: If you receive errors when you run AWS Command Line Interface (AWS CLI) commands, then see Troubleshoot AWS CLI errors. Also, make sure that you're using the most recent AWS CLI version.

Before you begin, complete the following:

Complete the following steps:

Note: You can perform the following steps from AWS CloudShell or any Linux environment.

  1. Create the following file:

    touch public_ipv4_recon.py
  2. Edit the file:

    vim public_ipv4_recon.py
  3. Copy and paste the following code into the file, and then save the file:

    #!/usr/bin/env python3
    import pprint
    import boto3, sys
    
    profile = boto3.Session(profile_name=sys.argv[1])
    aga = profile.client('globalaccelerator', region_name='us-west-2')
    ec2 = boto3.client('ec2')
    
    def global_public_ipv4_lookup(aga):
      try:
        # global accelerator
        next_token = None
        while True:
          if next_token:
            resource = aga.list_accelerators(
            NextToken = next_token
              )
          else:
            resource = aga.list_accelerators(
            )
          print('Describing world wide Global Accelerators...')
          print('Note: AWS Global Accelerators are billed in us-west-2....')
          print(f'Number of AGA: {len(resource["Accelerators"])}')
          print('-'*40)
          for item in resource["Accelerators"]:
            print(f'Name: {item["Name"]}')
            if 'IpSets' in item.keys():
              for ip in item["IpSets"][0]["IpAddresses"]:
                print(f'Public IPv4: {ip}')
            print(f'Status: {item["Status"]}')
            print()
          next_token = resource.get("NextToken")
          if next_token is None:
            break
        print()
        # custom_routing_accelerators
        next_token = None
        while True:
          if next_token:
            custom_routing = aga.list_custom_routing_accelerators(
              NextToken = next_token
            )
          else:
            custom_routing = aga.list_custom_routing_accelerators(
            )
          print('Describing world wide Custom Routing Accelerators...')
          print('Note: AWS Global Accelerators are billed in us-west-2....')
          print(f'Number of custom AGA: {len(custom_routing["Accelerators"])}')
          print('-'*40)
          for item in custom_routing["Accelerators"]:
            if 'IpSets' in item.keys():
              for ip in item["IpSets"][0]["IpAddresses"]:
                print(f'Public IPv4: {ip}')
            print(f'Status: {item["Status"]}')
            print()
          next_token = custom_routing.get("NextToken")
          if next_token is None:
            break
        print()
      except Exception as err:
        print(f'Error found: {err}...')
        pass
        
    def public_ipv4_lookup(ec2):
      try:
        # vpn
        next_token = None
        while True:
          if next_token:
            vpn = ec2.describe_vpn_connections(
                  NextToken = next_token
            )
          else:
            vpn = ec2.describe_vpn_connections(
            )
          print('Describing VPNs...')
          print(f'Number of Vpn connections: {len(vpn["VpnConnections"])}')
          print('-'*40)
          for item in vpn["VpnConnections"]:
            if 'VpnConnectionId' in item.keys():
              print(f'Vpn Id: {item["VpnConnectionId"]}')
              for ip in item["VgwTelemetry"]:
                print(f'Public ipv4: {ip["OutsideIpAddress"]}')
            print()
          next_token = vpn.get("NextToken")
          if next_token is None:
            break
        print()
        # elastic ip
        eip = ec2.describe_addresses(
        )
        print('Describing Elastic IPs...')
        print(f'Number of Elastic Ips: {len(eip["Addresses"])}')
        print('-'*40)
        for item in eip["Addresses"]:
          if 'AllocationId' in item.keys():
            print(f'Eip Id: {item["AllocationId"]}')
            print(f'Public ipv4: {item["PublicIp"]}')
            print()
        print()
        # network interfaces
        next_token = None
        while True:
          if next_token:
            interface = ec2.describe_network_interfaces(
            NextToken=next_token
              )
          else:
            interface = ec2.describe_network_interfaces(
            )
          print('Describing Network Interfaces...')
          print(f'Number of interfaces: {len(interface["NetworkInterfaces"])}')
          print('Only printing Interfaces with a public IPv4 address...')
          print('-'*40)
          for item in interface["NetworkInterfaces"]:
            #print(f'Private Ip: {item["PrivateIpAddress"]}')
            for ip in item["PrivateIpAddresses"]:
              if 'Association' not in ip.keys():
                pass
              else:
                print(f'Interface Id: {item["NetworkInterfaceId"]}')
                print(f'Description: {item["Description"]}')
                print(f'Status: {interface["NetworkInterfaces"][0]["Status"]}')
                print(f'Public Ip: {ip["Association"]["PublicIp"]}\n')
          next_token = interface.get("NextToken")
          if next_token is None:
            break
      except Exception as err:
        print(f'Error found: {err}...')
        pass
    
    # Run code
    if len(sys.argv) < 3 or not sys.argv[2]:
      global_public_ipv4_lookup(aga)
      regions_list = ec2.describe_regions(
          AllRegions=False
      )
      for region in regions_list['Regions']:
        if region["OptInStatus"] == 'opted-in' or 'opt-in-not-required':
          print(f'\n**********-[{region["RegionName"]}]-**********\n')
          public_ipv4_lookup(
            ec2=profile.client('ec2', region_name=region["RegionName"])
            )
    elif sys.argv[2]:
      #ec2 = profile.client('ec2', region_name=sys.argv[2])
      global_public_ipv4_lookup(aga)
      public_ipv4_lookup(
        ec2=profile.client('ec2', region_name=sys.argv[2])
        )
  4. Run the script: 
    Note: Replace example-cli profile with the name of the configured AWS CLI profile or any profile name defined in the .aws/credentials file. Replace example-region with the required Region.
    To check in all Regions, use this command:

    # python3 public_ipv4_recon.py <example-cli-profile>

    To check a specific Region, use this command:

    # python3 public_ipv4_recon.py <example-cli-profile> <example-region>

Note: You might receive the following error when you run the script. This error indicates that you might not be authorized to run the request or that the Region is turned off for your account.

"Error found: An error occurred (AuthFailure) when calling the <API> operation: AWS was not able to validate the provided access credentials..."

Optimize public IPv4 addresses usage and adopt IPv6 addresses

To optimize costs, enhance your current architecture to minimize the use of public IPv4 addresses. Also, it's a best practice to migrate to IPv6 soon. Migration to IPv6 is a cost-effective solution without charges for IP addresses.

AWS OFFICIAL
AWS OFFICIALUpdated a month ago