これはどの AWS サービスの IP アドレスですか?

これはどの AWS サービスの IP アドレスですか?

Clock Icon2025.03.06

困っていた内容

この IP アドレスはどの AWS サービスのものでしょうか。この IP アドレスを利用しているサービスを調べる方法がありましたらご教示ください。

どう対応すればいいの?

AWS が所有するパブリック IP アドレスの一覧は ip-ranges.json に CIDR 形式で公開されておりますので、こちらを元にお客様で当該 IP アドレスがどのサービスの一覧に含まれるかご確認ください。

より効率的な確認方法

自分の目だけで IP アドレスがこのリストに含まれているかを確認するのは時間が掛かるため、この作業を自動化する方法をご紹介します。

例えば、 35.73.115.135 は AWS が所有するパブリック IP アドレスの一つであり、 東京リージョンの API Gateway で利用されている IP アドレスですが、この IP アドレスが含まれる IP 範囲はこのファイル内に合計で 3 つもあります。(2025/03/06 現在)

// 1.
{
  "ip_prefix": "35.73.115.128/25",
  "region": "ap-northeast-1",
  "service": "API_GATEWAY",
  "network_border_group": "ap-northeast-1"
},

// 2.
{
  "ip_prefix": "35.72.0.0/13",
  "region": "ap-northeast-1",
  "service": "EC2",
  "network_border_group": "ap-northeast-1"
},

// 3.
{
  "ip_prefix": "35.72.0.0/13",
  "region": "ap-northeast-1",
  "service": "AMAZON",
  "network_border_group": "ap-northeast-1"
},

これらのうち最も具体的な IP アドレスの範囲が利用サービスとなるため、今回の場合は上記の 1. である API Gateway が利用サービスであることが確認できます。

単純にどのサービスか関わらず AWS 所有のものかを確認するだけであれば、いずれかの IP アドレス範囲に含まれることだけを確認すればよいですが、なるべく具体的にサービス名まで調べたい場合には、上記の IP アドレス範囲の具体性まで確認する必要があります。

調べてみた

Node.js で利用可能な npm モジュールである ipaddr.js を利用して、 IP アドレス範囲の具体性を加味しながら IP アドレスを調べてみたいと思います。

npm プロジェクトを新規作成し、 ipaddr.js をインストールしておきます。

npm init
# aws-ip-checker.mjs を entrypoint となるようにします。
npm i -D ipaddr.js

今回作成したソースコードは以下です。やや長いのでポイントを説明すると、 調べたい IP アドレスが ip-ranges.json から取得した IP アドレス範囲に含まれるかを ipaddr.js で確認し、複数マッチしたら最も一致するプレフィックスが大きいものを表示するようにしています。

import ipaddr from 'ipaddr.js';

/**
 * AWS IP 範囲の JSON を取得する
 * @returns {Promise<Object>} - AWS IP 範囲の JSON オブジェクト
 */
async function fetchAwsIpRanges() {
  try {
    const response = await fetch('https://ip-ranges.amazonaws.com/ip-ranges.json');
    if (!response.ok) {
      throw new Error(`HTTP エラー: ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    throw `AWS IP 範囲の取得に失敗しました: ${error.message}`;
  }
}

/**
 * IP アドレスが CIDR 範囲に一致するかチェックする関数
 * @param {Object} checkIp - IP アドレス
 * @param {string} cidr - チェック対象の CIDR
 * @param {Object} prefix - プレフィックス情報
 * @returns {Object|null} - 一致した場合はマッチ情報、一致しない場合は null
 */
function checkIpAgainstCidr(checkIp, cidr, prefix) {
  const range = ipaddr.parseCIDR(cidr);

  if (checkIp.match(range)) {
    const [, prefixLengthStr] = cidr.split('/');
    const prefixLength = parseInt(prefixLengthStr, 10);

    return {
      prefixLength,
      ...prefix,
      cidr
    };
  }

  return null;
}

/**
 * IPv4 アドレスを AWS IP 範囲と照合する関数
 * @param {Object} checkIp - IP アドレス
 * @param {Object} ipRanges - AWS IP 範囲の JSON オブジェクト
 * @returns {Array} - 一致した CIDR 範囲の配列
 */
function matchIpv4(checkIp, ipRanges) {
  return ipRanges.prefixes
    .map(prefix => checkIpAgainstCidr(checkIp, prefix.ip_prefix, prefix))
    .filter(Boolean);
}

/**
 * IPv6 アドレスを AWS IP 範囲と照合する関数
 * @param {Object} checkIp - ipaddr.js でパースされた IP アドレス
 * @param {Object} ipRanges - AWS IP 範囲の JSON オブジェクト
 * @returns {Array} - 一致した CIDR 範囲の配列
 */
function matchIpv6(checkIp, ipRanges) {
  return ipRanges.ipv6_prefixes?.map(prefix => 
    checkIpAgainstCidr(checkIp, prefix.ipv6_prefix, prefix)
  ).filter(Boolean) ?? [];
}

/**
 * 一致結果からレスポンスオブジェクトを作成する関数
 * @param {string} ipToCheck - 確認したい IP アドレス
 * @param {Array} matches - 一致した CIDR 範囲の配列
 * @returns {Object} - 結果を含むオブジェクト
 */
function createResponse(ipToCheck, matches) {
  if (matches.length === 0) {
    return {
      ip: ipToCheck,
      isAwsIp: false,
      service: null,
      region: null
    };
  }

  const sortedMatches = [...matches].sort((a, b) => b.prefixLength - a.prefixLength);
  const [bestMatch] = sortedMatches;

  const { service, region, cidr, prefixLength } = bestMatch;

  return {
    ip: ipToCheck,
    isAwsIp: true,
    service,
    region,
    cidr,
    prefixLength,
    allMatches: sortedMatches
  };
}

/**
 * 指定された IP アドレスが AWS IP 範囲に含まれるか確認する関数
 * @param {string} ipToCheck - 確認したい IP アドレス
 * @returns {Promise<Object>} - 結果を含むオブジェクト
 */
async function checkIfAwsIp(ipToCheck) {
  try {
    const ipRanges = await fetchAwsIpRanges();
    const checkIp = ipaddr.parse(ipToCheck);

    const matches = checkIp.kind() === 'ipv4' 
      ? matchIpv4(checkIp, ipRanges)
      : checkIp.kind() === 'ipv6' 
        ? matchIpv6(checkIp, ipRanges)
        : [];

    return createResponse(ipToCheck, matches);
  } catch (error) {
    throw `エラーが発生しました: ${error}`;
  }
}

/**
 * 結果を表示する関数
 * @param {Object} result - 結果
 */
function displayResult(result) {
  const { ip, isAwsIp, service, region, cidr, prefixLength, allMatches } = result;

  if (isAwsIp) {
    console.log(`${ip} は AWS の ${service} サービス (${region} リージョン) の IP アドレスです`);
    console.log(`最も具体的にマッチする AWS IP 範囲: ${cidr} (プレフィックス長: ${prefixLength})`);

    if (allMatches?.length > 1) {
      console.log('\n他のマッチする AWS IP範囲:');

      let i = 0;
      for (const match of allMatches) {
        if (i++ === 0) continue;

        const { cidr, service, region, prefixLength } = match;
        console.log(`- ${cidr} (${service}, ${region}, プレフィックス長: ${prefixLength})`);
      }
    }
  } else {
    console.log(`${ip} は AWS の IP アドレスではありません`);
  }
}

// メイン処理
async function main() {
  const [,, ipToCheck] = process.argv;

  if (!ipToCheck) {
    console.log('使用方法: node aws-ip-checker.js <IPアドレス>');
    process.exit(1);
  }

  try {
    const result = await checkIfAwsIp(ipToCheck);
    displayResult(result);
  } catch (error) {
    console.error(error);
  }
}

await main();

試しに 35.73.115.135 をこのプログラムで調べてみると、意図どおり IP アドレス範囲の具体性を加味しながら API_GATEWAY 、つまり API Gateway のものであることが確認できました。

node aws-ip-checker.mjs 35.73.115.135
35.73.115.135 は AWS の API_GATEWAY サービス (ap-northeast-1 リージョン) の IP アドレスです
最も具体的にマッチする AWS IP 範囲: 35.73.115.128/25 (プレフィックス長: 25)

他のマッチする AWS IP範囲:
- 35.72.0.0/13 (AMAZON, ap-northeast-1, プレフィックス長: 13)
- 35.72.0.0/13 (EC2, ap-northeast-1, プレフィックス長: 13)

注意点

AWS では全てのサービスの IP アドレス範囲が明確に区切られてはいない点にご注意ください。そうしたサービスでは ip-ranges.json では service プロパティの値が AMAZON となり、他サービスと IP アドレス範囲が区別されない結果となることがあります。

参考資料

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.