[アップデート] AWS WAFでASN一致ルールがサポートされました

[アップデート] AWS WAFでASN一致ルールがサポートされました

Clock Icon2025.06.08

しばたです。

先日よりAWS WAFにおいてASN一致ルールがサポートされました。
AWSからのアナウンスはこちらになります。

https://aws.amazon.com/about-aws/whats-new/2025/06/asn-match-aws-waf/

本記事ではこの更新について解説します。

更新内容

今回の更新で新たにAWS WAFに対するリクエスト元のASN(Autonomous System Number)一致ルールを設定することが可能になりました。
これにより特定のASNから来る通信だけを許可(または拒否)する制御ができます。

過去に弊社KajiがLambda関数を使って同様のことをやっていますが、AWS WAF標準ルールでこれが実現可能になった感じです。

https://dev.classmethod.jp/articles/bgp-asn-ip-aws-waf/

詳細

細かい仕様については以下のドキュメントに記載されています。

AWS WAFではリクエスト元のASNをIPアドレスから決定するとされていますが、その具体的な実装については非公開でした。[1]
AWS自身が巨大なグローバルネットワークを抱えてるので元になるデータには困らないでしょうし精度も信頼できると思います。

リクエスト元のIPアドレスはソースIPおよびX-Forwarded-For等のヘッダに記載されたIPアドレスのどちらかを使えます。
ヘッダに記載されたIPが不正な値の場合のフォールバック処理も設定できます。

何らかの理由でIPアドレスからASNを決定できない場合はASN = 0として扱われ、ルール中に明示的に0を記述することでこのケースに対応可能です。

1つのルール中にASNは最大100個まで指定可能です。
消費するWCUは通常のルール同様1となります。

補足 : 認証の代わりにはならない、という話

ドキュメント中にわざわざ

Note
ASN matching supplements, but doesn't replace, standard authentication and authorization controls. We recommend that you implement authentication and authorization mechanisms, such as IAM, to verify the identity of all requests in your applications.

との注釈があり「この機能は認証の代わりにはならない」旨が記載されています。

個人的には当然だろうというお気持ちなのですが、この様な注釈がある以上誤解されることが多いのかもしれません。
本記事をご覧の皆さんも誤解なき様お願いします。

試してみた

ここからは実際に試してみます。

私の検証用AWSアカウントの東京リージョンにWeb ACLを一つ用意しました。
こちらに動作確認用のルールを作っていきます。

aws-waf-supports-asn-match-rules-01

Rule builderから「Regular rule」を選び、

aws-waf-supports-asn-match-rules-02

StatementのInspect欄に新たに「Originates from an ASN in」が増えているのでこれを選んでやります。

aws-waf-supports-asn-match-rules-03

まずは分かりやすくエラーとするために普通の人は使わないAS63802 : MIKAKA-EAST以外からの通信をブロックする設定にしてみます。
「ASNs」欄に指定のASNを記載するだけでOKです。

aws-waf-supports-asn-match-rules-04

aws-waf-supports-asn-match-rules-05

この状態で保護対象にアクセスすると当然ブロックされます。

aws-waf-supports-asn-match-rules-06

アクセスログはこんな感じになります。

クリックして展開
ブロック時のアクセスログ
{
    "timestamp": 1749358662914,
    "formatVersion": 1,
    "webaclId": "arn:aws:wafv2:ap-northeast-1:xxxxxxxxxxxx:regional/webacl/test-waf/434fddf9-18cc-4994-b74b-a5b45800e793",
    "terminatingRuleId": "test-asn-rule",
    "terminatingRuleType": "REGULAR",
    "action": "BLOCK",
    "terminatingRuleMatchDetails": [],
    "httpSourceName": "APPRUNNER",
    "httpSourceId": "xxxxxxxxxxxx:eb6c49a6d1be445888fb0ec14dc3f91b",
    "ruleGroupList": [],
    "rateBasedRuleList": [],
    "nonTerminatingMatchingRules": [],
    "requestHeadersInserted": null,
    "responseCodeSent": null,
    "httpRequest": {
        "clientIp": "153.144.xx.xx",
        "country": "JP",
        "headers": [
            {
                "name": "Host",
                "value": "xxxxxxxxxx.ap-northeast-1.awsapprunner.com"
            },
            {
                "name": "Cache-Control",
                "value": "max-age=0"
            },
            {
                "name": "sec-ch-ua",
                "value": "\"Microsoft Edge\";v=\"137\", \"Chromium\";v=\"137\", \"Not/A)Brand\";v=\"24\""
            },
            {
                "name": "sec-ch-ua-mobile",
                "value": "?0"
            },
            {
                "name": "sec-ch-ua-platform",
                "value": "\"Windows\""
            },
            {
                "name": "DNT",
                "value": "1"
            },
            {
                "name": "Upgrade-Insecure-Requests",
                "value": "1"
            },
            {
                "name": "User-Agent",
                "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0"
            },
            {
                "name": "Accept",
                "value": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7"
            },
            {
                "name": "Sec-Fetch-Site",
                "value": "cross-site"
            },
            {
                "name": "Sec-Fetch-Mode",
                "value": "navigate"
            },
            {
                "name": "Sec-Fetch-User",
                "value": "?1"
            },
            {
                "name": "Sec-Fetch-Dest",
                "value": "document"
            },
            {
                "name": "Accept-Encoding",
                "value": "gzip, deflate, br, zstd"
            },
            {
                "name": "Accept-Language",
                "value": "en-US,en;q=0.9"
            },
            {
                "name": "x-forwarded-for",
                "value": "153.144.xx.xx"
            },
            {
                "name": "x-forwarded-proto",
                "value": "http"
            },
            {
                "name": "x-request-id",
                "value": "beb05cfb-7cf3-4be5-b7df-5ea326048baa"
            }
        ],
        "uri": "/",
        "args": "",
        "httpVersion": "HTTP/1.1",
        "httpMethod": "GET",
        "requestId": "beb05cfb-7cf3-4be5-b7df-5ea326048baa",
        "fragment": "",
        "scheme": "",
        "host": ""
    },
    "clientAsn": 4713
}

本ルールが評価されるとログに新たにclientAsnプロパティが増えリクエスト元のASNが分かります。
(ルールが評価されない場合はclientAsnは増えません)

ログより抜粋
"clientAsn": 4713

今回は私の自宅から検証しているのでプロバイダーのASN(AS4713 : OCN)が記録されていました。

続けてルールにこのASN(4713)を増やしてアクセス可能にしてみます。
複数ASNを記述する際は改行区切りにします。

aws-waf-supports-asn-match-rules-07
ASN 4713を追記

これで無事私の自宅プロバイダー(OCN)から接続可能になりました。

aws-waf-supports-asn-match-rules-08

アクセスログはこんな感じです。

クリックして展開
成功時のアクセスログ
{
    "timestamp": 1749359376798,
    "formatVersion": 1,
    "webaclId": "arn:aws:wafv2:ap-northeast-1:xxxxxxxxxxxx:regional/webacl/test-waf/434fddf9-18cc-4994-b74b-a5b45800e793",
    "terminatingRuleId": "Default_Action",
    "terminatingRuleType": "REGULAR",
    "action": "ALLOW",
    "terminatingRuleMatchDetails": [],
    "httpSourceName": "APPRUNNER",
    "httpSourceId": "xxxxxxxxxxxx:eb6c49a6d1be445888fb0ec14dc3f91b",
    "ruleGroupList": [],
    "rateBasedRuleList": [],
    "nonTerminatingMatchingRules": [],
    "requestHeadersInserted": null,
    "responseCodeSent": null,
    "httpRequest": {
        "clientIp": "153.144.xx.xx",
        "country": "JP",
        "headers": [
            {
                "name": "Host",
                "value": "xxxxxxxxxx.ap-northeast-1.awsapprunner.com"
            },
            {
                "name": "sec-ch-ua-platform",
                "value": "\"Windows\""
            },
            {
                "name": "If-None-Match",
                "value": "\"1749349103.0-9429-2185759178\""
            },
            {
                "name": "User-Agent",
                "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 Edg/137.0.0.0"
            },
            {
                "name": "sec-ch-ua",
                "value": "\"Microsoft Edge\";v=\"137\", \"Chromium\";v=\"137\", \"Not/A)Brand\";v=\"24\""
            },
            {
                "name": "DNT",
                "value": "1"
            },
            {
                "name": "If-Modified-Since",
                "value": "Sun, 08 Jun 2025 02:18:23 GMT"
            },
            {
                "name": "sec-ch-ua-mobile",
                "value": "?0"
            },
            {
                "name": "Accept",
                "value": "text/css,*/*;q=0.1"
            },
            {
                "name": "Sec-Fetch-Site",
                "value": "same-origin"
            },
            {
                "name": "Sec-Fetch-Mode",
                "value": "no-cors"
            },
            {
                "name": "Sec-Fetch-Dest",
                "value": "style"
            },
            {
                "name": "Referer",
                "value": "https://xxxxxxxxxx.ap-northeast-1.awsapprunner.com/"
            },
            {
                "name": "Accept-Encoding",
                "value": "gzip, deflate, br, zstd"
            },
            {
                "name": "Accept-Language",
                "value": "en-US,en;q=0.9"
            },
            {
                "name": "x-forwarded-for",
                "value": "153.144.xx.xx"
            },
            {
                "name": "x-forwarded-proto",
                "value": "http"
            },
            {
                "name": "x-request-id",
                "value": "a5f03775-19f3-425f-a457-2eb2e14a83f8"
            }
        ],
        "uri": "/static/simple.min.css",
        "args": "",
        "httpVersion": "HTTP/1.1",
        "httpMethod": "GET",
        "requestId": "a5f03775-19f3-425f-a457-2eb2e14a83f8",
        "fragment": "",
        "scheme": "",
        "host": ""
    },
    "clientAsn": 4713
}

最後に

以上となります。

具体的な例までは挙げませんがASNを基にアクセス制御したいケースはそれなりにあると思います。
AWS WAF標準ルールで簡単に設定できる様になったので気になる方はぜひ試してみてください。

脚注
  1. ちなみに前掲のDevelopersIOの記事ではBGPview APIを使ってASNからIPアドレスのPrefixを取得しています ↩︎

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.