[アップデート] AWS WAFでより詳細な地理的一致を使える様になりました

2022.11.03

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

しばたです。

本日よりAWS WAFの地理的一致ルールステートメントで国コードおよび地域コードのラベルが付与される様になりました。

AWSからのアナウンスはこちらになります。

どういうことか?

AWS WAFに従来からある地理的一致ルールステートメント(国コードを判別するステートメント)を評価した後に国コードおよび地域コードがラベルとして付与され、後続のルールでそのラベルを使った詳細な条件判定ができる様になりました。

付与されるラベルは、オリジンIPかフォーワードされたIPかによって変わり

  • オリジンIP
    • awswaf:clientip:geo:country:国コード
    • awswaf:clientip:geo:region:国コード-地域コード
  • フォーワードされたIP
    • awswaf:forwardedip:geo:country:国コード
    • awswaf:forwardedip:geo:region:国コード-地域コード

の2種2パターンとなります。

国コードおよび地域コードはISO 3166-2で規定される値となり、日本であれば都道府県コードとなります。
例えば北海道からのアクセスであれば

  • awswaf:clientip:geo:country:JP
  • awswaf:clientip:geo:region:JP-01 (01:北海道)

といったラベルが付与されます。

注意事項

私が動作確認した限りではこのラベルが付与されるのは地理的一致ルールが評価されたであり、ラベルを実際に使えるのは次以降のルールになります。
このため、1つの地理的一致ルールの中でAND条件でラベルを使おうとしても期待した動作になりませんでした。

(上図の様な記述をしてもこのルール内ではラベルが付与されてない様で期待した動作にならない)

AWSのドキュメントを見ても、最初に地理的一致ルールをCountモードで動作させてるのでそういうものなんだと思います。

実際の環境でこの機能を使う際はルールグループの形でルールをまとめたほうが良さそうです。

他にもCloudFrontの地理制限と併用する場合においてCloudFront側でブロックされたリクエストはAWS WAFに到達しないので注意が必要とのことでした。

試してみた

それでは早速試してみます。

今回はCloudFront + S3を使いペライチのWEBサイト(https:// example.shibata.tech)を用意し、そこにAWS WAF v2をアタッチしました。
ACLの名前はtest-waf-aclとし、動作確認をしやすくするために既定の動作をBlockにしています。

この時点ではルールが一つもないためアクセスしても必ずブロックされます。

今回は「北海道からのみアクセス可能なルール」を作ってみることにします。

ルールグループの作成

先述の通り地域コードのラベルを使うには最低2つのルールが必要となるので、ルールグループの形でまとめます。
(なお、ルールグループにまとめること自体は必須ではありません。)

ルールグループ名は「allow-from-hokkaido」としています。

最初のルールを作ります。
名前は「block-outside-japan」とし、このルールで地理的一致ルールステートメントを使い日本国外からのアクセスをブロックします。

次に2つめのルールを作ります。
名前は「allow-from-hokkaido」とし、ここでawswaf:clientip:geo:region:JP-01のラベルが付与されている場合アクセスを許可する条件を記述します。

あとはこの2つのルールを「block-outside-japan→allow-from-hokkaido」の評価順にしてルールグループを作成します。
評価順が重要ですので順序を間違わない様に気を付けてください。

最後に作成したルールグループをACLに登録します。

これでルールが有効になりました。

動作確認

ルールが有効になったので私の自宅(札幌)からアクセスすると無事サイトが表示されました。

東京リージョンに立てたEC2(東京)からアクセスするとブロックされます。

もちろん日本国外からアクセスした場合もブロックされます。

ログで確認

ブラウザの画面だけだと正直わかりにくいと思います。
ここからは実際のAWS WAFログを見て結果をチェックします。

札幌からのアクセス (許可)

札幌からのアクセスログはこんな感じです。
allow-from-hokkaidoルールでアクセス許可されているのと、awswaf:clientip:geo:region:JP-01ラベルが付いていることが見て取れます。

{
    "timestamp": 1667448725866,
    "formatVersion": 1,
    "webaclId": "arn:aws:wafv2:us-east-1:000000000000:global/webacl/test-waf-acl/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "terminatingRuleId": "allow-from-hokkaido",
    "terminatingRuleType": "GROUP",
    "action": "ALLOW",
    "terminatingRuleMatchDetails": [],
    "httpSourceName": "CF",
    "httpSourceId": "XXXXXXXXXXXXXX",
    "ruleGroupList": [
        {
            "ruleGroupId": "arn:aws:wafv2:us-east-1:000000000000:global/rulegroup/allow-from-hokkaido/af65889f-60f7-4f68-a9ad-6df6721af54e",
            "terminatingRule": {
                "ruleId": "allow-from-hokkaido",
                "action": "ALLOW",
                "ruleMatchDetails": null
            },
            "nonTerminatingMatchingRules": [],
            "excludedRules": null,
            "customerConfig": null
        }
    ],
    "rateBasedRuleList": [],
    "nonTerminatingMatchingRules": [],
    "requestHeadersInserted": null,
    "responseCodeSent": null,
    "httpRequest": {
        "clientIp": "xx.xx.xx.xx (札幌のIP)",
        "country": "JP",
        "headers": [
            {
                "name": "host",
                "value": "example.shibata.tech"
            },
            {
                "name": "sec-ch-ua",
                "value": "\"Microsoft Edge\";v=\"107\", \"Chromium\";v=\"107\", \"Not=A?Brand\";v=\"24\""
            },
            {
                "name": "sec-ch-ua-mobile",
                "value": "?0"
            },
            {
                "name": "user-agent",
                "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.26"
            },
            {
                "name": "sec-ch-ua-platform",
                "value": "\"Windows\""
            },
            {
                "name": "accept",
                "value": "image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"
            },
            {
                "name": "sec-fetch-site",
                "value": "same-origin"
            },
            {
                "name": "sec-fetch-mode",
                "value": "no-cors"
            },
            {
                "name": "sec-fetch-dest",
                "value": "image"
            },
            {
                "name": "referer",
                "value": "https://example.shibata.tech/"
            },
            {
                "name": "accept-encoding",
                "value": "gzip, deflate, br"
            },
            {
                "name": "accept-language",
                "value": "en-US,en;q=0.9"
            }
        ],
        "uri": "/favicon.ico",
        "args": "",
        "httpVersion": "HTTP/2.0",
        "httpMethod": "GET",
        "requestId": "m3Gl0Pnt3iv6J8V651nbpeUB4ZdLUd4znQFwzJo4xsBQGd_ekxKhEA=="
    },
    "labels": [
        {
            "name": "awswaf:clientip:geo:region:JP-01"
        },
        {
            "name": "awswaf:clientip:geo:country:JP"
        }
    ]
}

東京からのアクセス (ブロック)

東京からのアクセスはこんな感じです。
デフォルトアクションでブロックされたせいかラベルが付いていませんが、アクセス元がJPであることが見て取れます。

{
    "timestamp": 1667448732662,
    "formatVersion": 1,
    "webaclId": "arn:aws:wafv2:us-east-1:000000000000:global/webacl/test-waf-acl/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "terminatingRuleId": "Default_Action",
    "terminatingRuleType": "REGULAR",
    "action": "BLOCK",
    "terminatingRuleMatchDetails": [],
    "httpSourceName": "CF",
    "httpSourceId": "XXXXXXXXXXXXXX",
    "ruleGroupList": [
        {
            "ruleGroupId": "arn:aws:wafv2:us-east-1:000000000000:global/rulegroup/allow-from-hokkaido/af65889f-60f7-4f68-a9ad-6df6721af54e",
            "terminatingRule": null,
            "nonTerminatingMatchingRules": [],
            "excludedRules": null,
            "customerConfig": null
        }
    ],
    "rateBasedRuleList": [],
    "nonTerminatingMatchingRules": [],
    "requestHeadersInserted": null,
    "responseCodeSent": null,
    "httpRequest": {
        "clientIp": "13.112.xx.xx (東京のIP)",
        "country": "JP",
        "headers": [
            {
                "name": "host",
                "value": "example.shibata.tech"
            },
            {
                "name": "sec-ch-ua",
                "value": "\"Microsoft Edge\";v=\"107\", \"Chromium\";v=\"107\", \"Not=A?Brand\";v=\"24\""
            },
            {
                "name": "sec-ch-ua-mobile",
                "value": "?0"
            },
            {
                "name": "user-agent",
                "value": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36 Edg/107.0.1418.26"
            },
            {
                "name": "sec-ch-ua-platform",
                "value": "\"Windows\""
            },
            {
                "name": "accept",
                "value": "image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"
            },
            {
                "name": "sec-fetch-site",
                "value": "same-origin"
            },
            {
                "name": "sec-fetch-mode",
                "value": "no-cors"
            },
            {
                "name": "sec-fetch-dest",
                "value": "image"
            },
            {
                "name": "referer",
                "value": "https://example.shibata.tech/"
            },
            {
                "name": "accept-encoding",
                "value": "gzip, deflate, br"
            },
            {
                "name": "accept-language",
                "value": "ja"
            }
        ],
        "uri": "/favicon.ico",
        "args": "",
        "httpVersion": "HTTP/2.0",
        "httpMethod": "GET",
        "requestId": "o4E-JaXyJ8B9dpC23PefiqtV3bPyTVvg2Ymd219A7COwRy5-X1AcvQ=="
    }
}

一応接続元IPの地理情報を確認すると東京になります。

国外からのアクセス (ブロック)

国外からのアクセスはこんな感じです。
block-outside-japanルールでブロックされているのと、ラベルawswaf:clientip:geo:region:US-VAが付いておりバージニア州からのアクセスであることが分かります。

{
    "timestamp": 1667448741894,
    "formatVersion": 1,
    "webaclId": "arn:aws:wafv2:us-east-1:000000000000:global/webacl/test-waf-acl/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
    "terminatingRuleId": "allow-from-hokkaido",
    "terminatingRuleType": "GROUP",
    "action": "BLOCK",
    "terminatingRuleMatchDetails": [],
    "httpSourceName": "CF",
    "httpSourceId": "XXXXXXXXXXXXXX",
    "ruleGroupList": [
        {
            "ruleGroupId": "arn:aws:wafv2:us-east-1:000000000000:global/rulegroup/allow-from-hokkaido/af65889f-60f7-4f68-a9ad-6df6721af54e",
            "terminatingRule": {
                "ruleId": "block-outside-japan",
                "action": "BLOCK",
                "ruleMatchDetails": null
            },
            "nonTerminatingMatchingRules": [],
            "excludedRules": null,
            "customerConfig": null
        }
    ],
    "rateBasedRuleList": [],
    "nonTerminatingMatchingRules": [],
    "requestHeadersInserted": null,
    "responseCodeSent": null,
    "httpRequest": {
        "clientIp": "xx.xx.xx.xx (アメリカのIP)",
        "country": "US",
        "headers": [
            {
                "name": "host",
                "value": "example.shibata.tech"
            },
            {
                "name": "user-agent",
                "value": "curl/7.79.1"
            },
            {
                "name": "accept",
                "value": "*/*"
            }
        ],
        "uri": "/",
        "args": "",
        "httpVersion": "HTTP/2.0",
        "httpMethod": "GET",
        "requestId": "_OEDqCEkjtPv4SBcyDbRpx4DdPyA8JmEqO1vgIn2gb9OWbHFPdFdTw=="
    },
    "labels": [
        {
            "name": "awswaf:clientip:geo:country:US"
        },
        {
            "name": "awswaf:clientip:geo:region:US-VA"
        }
    ]
}

最後に

以上となります。

私がAWS WAFのラベルを扱い慣れていないせいかちょっとクセのある仕様に思えました。
とはいえ地理情報をより柔軟に扱いたい場合に非常に便利に使えることでしょう。