AWS IP Address Ranges

We had the need to find AWS IP Addresess for a certain Service and Regions, and use them to route traffic over Amazons Direct Connect.
Luckily Amzon publishes the IP Ranges in Json Format.

  1. Shell Code
  2. Routes for cisco
    1. Shell
  3. AWS IP Ranges Syntax
    1. Syntax
      1. syncToken
      2. prefixes
      3. ipv6_prefixes
      4. ip_prefix
      5. ipv6_prefix
      6. network_border_group
      7. region
      8. service
    2. Filtering the JSON file
      1. Linux
        1. Example 1. Get the creation date
        2. Example 2. Get the information for a specific Region
        3. Example 6. Get all IPv4 addresses for a specific service in a specific Region
        4. Example 7. Get information for a certain network border group
      2. Python
  4. Links

Shell Code

curl https://ip-ranges.amazonaws.com/ip-ranges.json | \
  jq -r '.prefixes[] | select(.service=="S3") | select(.network_border_group=="eu-central-1" ) | .ip_prefix'

Routes for cisco

We needed to have them on our Cisco Routers in a dedicated Routing instance (VRF).

Shell

# curl https://ip-ranges.amazonaws.com/ip-ranges.json | jq -r '.prefixes[] | select(.service=="S3") | select(.network_border_group=="eu-central-1" ) | .ip_prefix' | while read line ; do\
   echo ip route vrf vrf-aws-connect $(echo $line | cut -d '/' -f 1) $(~/bin/ipcalc -bn ${line} | grep Netmask | cut -f 2 -d ":" | cut -f 1 -d "=" | sed -e 's/ //gm') 10.255.112.121 name SAWS-S3-EU-CENTRAL-1 \
done

AWS IP Ranges Syntax

The Syntax per Amazon, can be found here: AWS IP address ranges.
All Rights below this point belong to Amazon Web Services, Inc.

{
  "syncToken": "0123456789",
  "createDate": "yyyy-mm-dd-hh-mm-ss",
  "prefixes": [
    {
      "ip_prefix": "cidr",
      "region": "region",
      "network_border_group": "network_border_group",
      "service": "subset"
    }
  ],
  "ipv6_prefixes": [
    {
      "ipv6_prefix": "cidr",
      "region": "region",
      "network_border_group": "network_border_group",
      "service": "subset"
    }
  ]  
}

Syntax

syncToken

The publication time, in Unix epoch time format.

Type: String

Example: "syncToken": "1416435608"

prefixes

The IP prefixes for the IPv4 address ranges.

Type: Array

ipv6_prefixes

The IP prefixes for the IPv6 address ranges.

Type: Array

ip_prefix

The public IPv4 address range, in CIDR notation. Note that AWS may advertise a prefix in more specific ranges. For example, prefix 96.127.0.0/17 in the file may be advertised as 96.127.0.0/21, 96.127.8.0/21, 96.127.32.0/19, and 96.127.64.0/18.

Type: String

Example: "ip_prefix": "198.51.100.2/24"

ipv6_prefix

The public IPv6 address range, in CIDR notation. Note that AWS may advertise a prefix in more specific ranges.

Type: String

Example: "ipv6_prefix": "2001:db8:1234::/64"

network_border_group

The name of the network border group, which is a unique set of Availability Zones or Local Zones from which AWS advertises IP addresses, or GLOBAL. Traffic for GLOBAL services can be attracted to or originate from multiple (up to all) Availability Zones or Local Zones from which AWS advertises IP addresses.

Type: String

Example: "network_border_group": "us-west-2-lax-1"

region

The AWS Region or GLOBAL. Traffic for GLOBAL services can be attracted to or originate from multiple (up to all) AWS Regions.

Type: String

Valid values: af-south-1 | ap-east-1 | ap-northeast-1 | ap-northeast-2 | ap-northeast-3 | ap-south-1 | ap-south-2 | ap-southeast-1 | ap-southeast-2 | ap-southeast-3 | ap-southeast-4 | ca-central-1 | cn-north-1 | cn-northwest-1 | eu-central-1 | eu-central-2 | eu-north-1 | eu-south-1 | eu-south-2 | eu-west-1 | eu-west-2 | eu-west-3 | me-central-1 | me-south-1 | sa-east-1 | us-east-1 | us-east-2 | us-gov-east-1 | us-gov-west-1 | us-west-1 | us-west-2 | GLOBAL

Example: "region": "us-east-1"

service

The subset of IP address ranges. The addresses listed for API_GATEWAY are egress only. Specify AMAZON to get all IP address ranges (meaning that every subset is also in the AMAZON subset). However, some IP address ranges are only in the AMAZON subset (meaning that they are not also available in another subset).

Type: String

Valid values: AMAZON | AMAZON_APPFLOW | AMAZON_CONNECT | API_GATEWAY | CHIME_MEETINGS | CHIME_VOICECONNECTOR | CLOUD9 | CLOUDFRONT | CLOUDFRONT_ORIGIN_FACING | CODEBUILD | DYNAMODB | EBS | EC2 | EC2_INSTANCE_CONNECT | GLOBALACCELERATOR | KINESIS_VIDEO_STREAMS | MEDIA_PACKAGE_V2 | ROUTE53 | ROUTE53_HEALTHCHECKS | ROUTE53_HEALTHCHECKS_PUBLISHING | ROUTE53_RESOLVER | S3 | WORKSPACES_GATEWAYS

Example: "service": "AMAZON"

Filtering the JSON file

Linux
Example 1. Get the creation date
$ jq .createDate < ip-ranges.json "2016-02-18-17-22-15"
Example 2. Get the information for a specific Region
$ jq '.prefixes[] | select(.region=="us-east-1")' < ip-ranges.json

{
  "ip_prefix": "23.20.0.0/14",
  "region": "us-east-1",
  "network_border_group": "us-east-1",
  "service": "AMAZON"
},
{
  "ip_prefix": "50.16.0.0/15",
  "region": "us-east-1",
  "network_border_group": "us-east-1",
  "service": "AMAZON"
},
{
  "ip_prefix": "50.19.0.0/16",
  "region": "us-east-1",
  "network_border_group": "us-east-1",
  "service": "AMAZON"
},
...
Example 6. Get all IPv4 addresses for a specific service in a specific Region

$ jq -r '.prefixes[] | select(.region=="us-east-1") | select(.service=="CODEBUILD") | .ip_prefix' < ip-ranges.json 34.228.4.208/28

Example 7. Get information for a certain network border group

$ jq -r '.prefixes[] | select(.region=="us-west-2") | select(.network_border_group=="us-west-2-lax-1") | .ip_prefix' < ip-ranges.json 70.224.192.0/18 52.95.230.0/24 15.253.0.0/16 ...

Python

The following python script shows you how to get the IP addresses that are in the AMAZON list but not the EC2 list. Copy the script and save it in a file named get_ips.py.

#!/usr/bin/env python
import requests

ip_ranges = requests.get('https://ip-ranges.amazonaws.com/ip-ranges.json').json()['prefixes']
amazon_ips = [item['ip_prefix'] for item in ip_ranges if item["service"] == "AMAZON"]
ec2_ips = [item['ip_prefix'] for item in ip_ranges if item["service"] == "EC2"]

amazon_ips_less_ec2=[]
     
for ip in amazon_ips:
    if ip not in ec2_ips:
        amazon_ips_less_ec2.append(ip)

for ip in amazon_ips_less_ec2: print(str(ip))

You can run this script as follows:

$ python ./get_ips.py
13.32.0.0/15
13.35.0.0/16
13.248.0.0/20
13.248.16.0/21
13.248.24.0/22
13.248.28.0/22
27.0.0.0/22
43.250.192.0/24
43.250.193.0/24
...

Photo by Taylor Vick on Unsplash