
AWS IP アドレス 範囲ファイルを IP アドレスの前方一致で絞り込んだりレンジを一緒に表示したりしてみた
コンバンハ、千葉(幸)です。
AWSが利用するIPアドレスの情報はip-ranges.jsonとして公開されています。
AWSを利用していく中で、「このIPアドレスってAWSが保有するものなのか?」「どのサービス用のIPアドレスなのか?」が気になることがあります。「このサービスが取りうるIP範囲を知りたい」ではなく、 「このIPアドレスが何で使われているかを知りたい」 という方向です。
ip-ranges.jsonからお目当てのIPアドレスを絞り込んでいくのがちょっと楽になる方法を紹介します。
なお、今回はIPv4アドレスを対象にしています。以降も単に「IPアドレス」と呼称します。
ポイント
- curlによる出力をjqで整形する
- IPアドレスの文字列の前方一致で絞り込む
- IPアドレスでソートする
- (オプション)ipcalcでネットワークアドレス〜ブロードキャストアドレスのレンジを計算し表示する
なお、ローカルにファイル保存せず、都度curlでダウンロードをする前提でコマンドを考えています。一度の実行で4MB弱のダウンロードが発生します(2025/03/31現在)。繰り返し実行する場合には、一度ローカルにファイルとして保存し、そのファイルに対してjqを実行すると良いでしょう。
動作確認環境
- macOS
- curl 8.7.1
- jq 1.6
- ipcalc 0.51
- AWS CloudShell
- curl 8.5.0
- jq 不明
- ipcalc 1.0.1
ip-ranges.jsonをIPアドレスの前方一致でフィルタリングする
「52.192.xx.xx」というIPアドレスについて調べたかったとします。
jqのstartswith関数を用いてフィルタリングできます。
curl -s https://ip-ranges.amazonaws.com/ip-ranges.json \
| jq '.prefixes[] | select(.ip_prefix | startswith("52.192"))'
{
"ip_prefix": "52.192.0.0/15",
"region": "ap-northeast-1",
"service": "AMAZON",
"network_border_group": "ap-northeast-1"
}
{
"ip_prefix": "52.192.0.0/15",
"region": "ap-northeast-1",
"service": "EC2",
"network_border_group": "ap-northeast-1"
}
ここでは第二オクテットまでを指定していますが、第三オクテットまで含めたり、第三オクテットの1桁目までだけ含めたり、ということもできます。
ip-ranges.jsonをtsvで出力する
該当する結果が多い場合には、ひとつのIPプレフィックスの情報を1行で確認したくなります。
jqによる出力でtsv形式を指定します。(フィルタリング結果量を多くするために、「52.19」までに拡大)
curl -s https://ip-ranges.amazonaws.com/ip-ranges.json \
| jq -r '.prefixes[] | select(.ip_prefix | startswith("52.19"))
| [.ip_prefix, .region, .service, .network_border_group] | @tsv'
52.192.0.0/15 ap-northeast-1 AMAZON ap-northeast-1
52.194.0.0/15 ap-northeast-1 AMAZON ap-northeast-1
52.196.0.0/14 ap-northeast-1 AMAZON ap-northeast-1
52.195.198.0/23 ap-northeast-1 AMAZON ap-northeast-1
52.195.200.0/22 ap-northeast-1 AMAZON ap-northeast-1
52.19.124.0/23 eu-west-1 WORKSPACES_GATEWAYS eu-west-1
52.192.0.0/15 ap-northeast-1 EC2 ap-northeast-1
52.194.0.0/15 ap-northeast-1 EC2 ap-northeast-1
52.196.0.0/14 ap-northeast-1 EC2 ap-northeast-1
52.199.127.192/26 ap-northeast-1 CLOUDFRONT ap-northeast-1
ip-ranges.jsonをIPプレフィックスでソートする
デフォルトでは特にIPプレフィックスはソートされていません。せっかくなら昇順に並べたいものです。
Sort_by関数を組み込んでソートします。
curl -s https://ip-ranges.amazonaws.com/ip-ranges.json \
| jq -r '.prefixes | map(select(.ip_prefix | startswith("52.19")))
| sort_by(.ip_prefix | split("/")[0] | split(".") | map(tonumber))
| .[] | [.ip_prefix, .region, .service, .network_border_group] | @tsv'
52.19.124.0/23 eu-west-1 WORKSPACES_GATEWAYS eu-west-1
52.192.0.0/15 ap-northeast-1 AMAZON ap-northeast-1
52.192.0.0/15 ap-northeast-1 EC2 ap-northeast-1
52.194.0.0/15 ap-northeast-1 AMAZON ap-northeast-1
52.194.0.0/15 ap-northeast-1 EC2 ap-northeast-1
52.195.198.0/23 ap-northeast-1 AMAZON ap-northeast-1
52.195.200.0/22 ap-northeast-1 AMAZON ap-northeast-1
52.196.0.0/14 ap-northeast-1 AMAZON ap-northeast-1
52.196.0.0/14 ap-northeast-1 EC2 ap-northeast-1
52.199.127.192/26 ap-northeast-1 CLOUDFRONT ap-northeast-1
sort_by関数で行なっていること(Claude 3.7 Sonnetによる解説)
.ip_prefix
1. - 各エントリのIP_prefixフィールドを取得します
- 例:
"52.192.0.0/15"
split("/")[0]
2. - CIDR表記からスラッシュ(
/
)で分割し、最初の要素(IPアドレス部分)だけを取り出します - 例:
"52.192.0.0/15"
→"52.192.0.0"
split(".")
3. - IPアドレスをドット(
.
)で分割して配列にします - 例:
"52.192.0.0"
→["52", "192", "0", "0"]
map(tonumber)
4. - 配列の各要素(文字列)を数値に変換します
- 例:
["52", "192", "0", "0"]
→[52, 192, 0, 0]
sort_by(...)
5. - 上記の変換結果を使用して配列をソートします
- 配列の各要素を比較する際に、最初のオクテットから順に比較します
- 同じ値の場合は次のオクテットを比較します
なぜこの処理が必要か
単純な文字列としてIPアドレスをソートすると、辞書順(アルファベット順)でソートされるため、以下のような問題が発生します。
10.0.0.0 (文字列の先頭が"1")
2.0.0.0 (文字列の先頭が"2")
52.192.0.0 (文字列の先頭が"5")
しかし、IPアドレスとしては数値的に正しくソートすると以下のようになるべきです。
2.0.0.0 (最初のオクテットが2)
10.0.0.0 (最初のオクテットが10)
52.192.0.0 (最初のオクテットが52)
この式を使用することで、IPアドレスの各オクテットを数値として扱い、正しい数値順でソートすることができます。
ip-ranges.jsonのIPプレフィックスのレンジをあわせて表示する
たとえば「52.196.0.0/14」と言われた時に、それがどのIPアドレスのレンジを表すのかわたしはパッと計算できません。
ipcalcを間に挟むことで、IPレンジも一緒に表示してみます。
あらかじめipcalcをインストールしておきます。
brew install ipcalc
sudo dnf install ipcalc -y
コマンドも長くなってきたので、前方一致で検索したいIPアドレスを変数に格納する形式にします。
SEARCH_IP_PREFIX="52.19"
curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | \
jq -r --arg search_ip_prefix "$SEARCH_IP_PREFIX" '.prefixes |
map(select(.ip_prefix | startswith($search_ip_prefix))) |
sort_by(.ip_prefix | split("/")[0] | split(".") | map(tonumber)) |
.[] | [.ip_prefix, .region, .service, .network_border_group] | @tsv' | \
while IFS=$'\t' read -r prefix region service border_group; do
network=$(ipcalc "$prefix" | grep "Network:" | awk '{print $2}' | cut -d/ -f1)
broadcast=$(ipcalc "$prefix" | grep "Broadcast:" | awk '{print $2}')
ip_range="$network - $broadcast"
printf "%s\t%s\t%s\t%s\t%s\n" "$prefix" "$region" "$service" "$border_group" "$ip_range"
done
52.19.124.0/23 eu-west-1 WORKSPACES_GATEWAYS eu-west-1 52.19.124.0 - 52.19.125.255
52.192.0.0/15 ap-northeast-1 AMAZON ap-northeast-1 52.192.0.0 - 52.193.255.255
52.192.0.0/15 ap-northeast-1 EC2 ap-northeast-1 52.192.0.0 - 52.193.255.255
52.194.0.0/15 ap-northeast-1 AMAZON ap-northeast-1 52.194.0.0 - 52.195.255.255
52.194.0.0/15 ap-northeast-1 EC2 ap-northeast-1 52.194.0.0 - 52.195.255.255
52.195.198.0/23 ap-northeast-1 AMAZON ap-northeast-1 52.195.198.0 - 52.195.199.255
52.195.200.0/22 ap-northeast-1 AMAZON ap-northeast-1 52.195.200.0 - 52.195.203.255
52.196.0.0/14 ap-northeast-1 AMAZON ap-northeast-1 52.196.0.0 - 52.199.255.255
52.196.0.0/14 ap-northeast-1 EC2 ap-northeast-1 52.196.0.0 - 52.199.255.255
52.199.127.192/26 ap-northeast-1 CLOUDFRONT ap-northeast-1 52.199.127.192 - 52.199.127.255
一番右の5列目に、52.119.205.0 - 52.119.205.255
のような形でIPレンジを表示しています。(/32の場合は5列目が表示されません。)
全体の流れ(Claude 3.7 Sonnetによる解説)
1. AWS IP範囲情報の取得
curl -s https://ip-ranges.amazonaws.com/ip-ranges.json
curl
: URLからデータを取得するコマンド-s
: サイレントモード(進捗情報を表示しない)- AWSが公開しているIP範囲のJSON情報を取得
2. jqによるJSONデータの処理
jq -r --arg search_ip_prefix "$SEARCH_IP_PREFIX" '.prefixes |
map(select(.ip_prefix | startswith($search_ip_prefix))) |
sort_by(.ip_prefix | split("/")[0] | split(".") | map(tonumber)) |
.[] | [.ip_prefix, .region, .service, .network_border_group] | @tsv'
jq
: JSONデータを処理するためのコマンド-r
: 生の出力(引用符なし)--arg search_ip_prefix "$SEARCH_IP_PREFIX"
: 変数を渡す.prefixes
: JSONの"prefixes"配列を取得map(select(...))
: 指定したIPプレフィックスで始まるエントリをフィルタリングsort_by(...)
: IPアドレスを数値的に正しくソート.[]
: 配列の各要素を処理[.ip_prefix, .region, .service, .network_border_group]
: 必要なフィールドを配列に格納@tsv
: タブ区切り形式で出力
3. whileループによる各行の処理
while IFS=$'\t' read -r prefix region service border_group; do
...
done
IFS=$'\t'
: 入力フィールドの区切り文字をタブに設定read -r prefix...
: タブ区切りの入力を変数に読み込む- 各行(各IPプレフィックス)に対して処理を実行
4. ipcalcによるIPアドレス範囲の計算
network=$(ipcalc "$prefix" | grep "Network:" | awk '{print $2}' | cut -d/ -f1)
broadcast=$(ipcalc "$prefix" | grep "Broadcast:" | awk '{print $2}')
ipcalc
: IPアドレス計算ツールgrep "Network:"
: ネットワークアドレス行を抽出awk '{print $2}'
: 2番目のフィールド(IPアドレス)を抽出cut -d/ -f1
: CIDR表記からスラッシュ以降を削除- 同様にブロードキャストアドレスも取得
ip_range="$network - $broadcast"
: 範囲を「開始IP - 終了IP」形式で作成
5. 結果の整形と出力
printf "%s\t%s\t%s\t%s\t%s\n" "$prefix" "$region" "$service" "$border_group" "$ip_range"
printf
: フォーマット付きで出力%s\t
: 文字列をタブ区切りで出力- 5つのフィールドをタブ区切りで表示
ipcalcについて
ipcalcではたとえば以下のように各種情報が確認できます。
% ipcalc 52.19.124.0/23
Address: 52.19.124.0 00110100.00010011.0111110 0.00000000
Netmask: 255.255.254.0 = 23 11111111.11111111.1111111 0.00000000
Wildcard: 0.0.1.255 00000000.00000000.0000000 1.11111111
=>
Network: 52.19.124.0/23 00110100.00010011.0111110 0.00000000
HostMin: 52.19.124.1 00110100.00010011.0111110 0.00000001
HostMax: 52.19.125.254 00110100.00010011.0111110 1.11111110
Broadcast: 52.19.125.255 00110100.00010011.0111110 1.11111111
Hosts/Net: 510 Class A
今回はNetwork
(の/
以降を削ったもの)とBroadcast
の値を用いています。
ホストが取りうるIPレンジを出力、ということであればHostMin
とHostMax
を用いるのもよいでしょう。
番外編:ip-ranges.jsonのプレフィックス長ごとの数を確認する
/24
や/20
などのプレフィックス長がそれぞれどのくらいあるのか気になった時に調べる用です。
curl -s https://ip-ranges.amazonaws.com/ip-ranges.json | jq -r '.prefixes[].ip_prefix | split("/") | last' | sort | uniq -c | awk '{print "/" $2, $1}'
2025/03/31現在の結果はこちら。かなり頻繁に変わっているようです。
/11 4
/12 19
/13 42
/14 113
/15 303
/16 528
/17 101
/18 146
/19 78
/20 203
/21 302
/22 588
/23 548
/24 2031
/25 219
/26 507
/27 298
/28 348
/29 344
/30 179
/31 490
/32 1139
終わりに
AWS IPアドレス範囲をcurlやjqを使っていい感じに確認する方法の紹介でした。
「このIPアドレスってどのリージョンのどのサービス用だ?」などを調べたくなった時に思い出してください。
ローカルにダウンロードしたファイルを対象にjqで色々やるパターンは公式ドキュメントに載っていますので、こちらもあわせてご参考ください。
以上、チバユキ (@batchicchi)がお送りしました。
参考