AWS WAF のアクセスログをとりあえず S3 で確認したい

今回は AWS WAF（Web アプリケーションファイアウォール）を利用するうえで、何かあったときに WAF のログを確認する方法を知っておきたい方という方へ、S3 Select でアクセスが拒否されたログを確認する方法をお送りします。


## AWS WAF のログ出力先について
Web アプリケーションを保護する目的で AWS WAF を導入した場合、WAF のログを Kinesis Data Firehose 経由で S3 に保存することができます。
そして、S3 に保存された WAF ログを S3 の機能である S3 Select を利用して確認することができます。 

ちなみに、WAF のログの
出力先は Amazon S3、Amazon ElasticSearch、Amazon RedShift を指定できます。(2019年11月25日時点)
大量のログデータを確認する場合は、ElasticSearch と RedShift を選んでいきたいですね。


## WAFの設定方法
「WAF のアクセスログを Kinesis Data Firehose 経由で S3 に保存する」ために、今回は以下の流れで AWS を構築しました。

1. Kinesis Data Firehose を構築し、ログ出力先を S3 に設定
1. WAF を構築し、WAF のログ出力先を Kinesis に設定

※S3バケットは Kinesis の構築時に一緒に新規作成できます。
※Kinesis Data Firehoses は "aws-waf-logs-" で始まる名前にする必要があるので、注意が必要です。
> ウェブ ACL でログ記録を有効にするには  
> 1. Amazon Kinesis Data Firehose を「aws-waf-logs-」で始まるプレフィックスを使用して作成します (たとえば、aws-waf-logs-us-east-2-analytics)
[ウェブ ACL トラフィック情報のログ記録 - AWS WAF、AWS Firewall Manager、および AWS Shield アドバンスド](https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/logging.html)




## WAF で XSS (クロスサイトスクリプティング) 攻撃をブロックする
WAF には、XSS 攻撃をブロックするルールを設定しています。
今回は EC2 上に構築した検証用の Web サイトの URL に以下を追記してアクセスし、XSS 攻撃を行います。
`http://***.com/?%3CSCRIPT%3Ealert(%E2%80%9CCookie%E2%80%9D+document.cookie)%3C/SCRIPT%3E`

↓通常の URL だと問題なくアクセスできますが…
<img width="600" alt="2019-11-25_14h27_42.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385681/02b1b002-a50d-d442-58ba-0c173964e2e2.png">



↓ "403 Forbidden" と表示されアクセスできませんでした。ちゃんと攻撃がブロックされていますね。
(WAF でアプリケーションを保護していない場合はアクセスできてしまいます。)
<img width="600" alt="2019-11-25_17h13_18.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385681/d3d05f92-51c6-a559-bef8-973a01377a33.png">


↓ WAF のコンソール上でも簡易的ですがブロックされた内容が確認できました。
<img width="600" alt="2019-11-25_14h46_01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385681/eb059ba4-e951-3a63-8884-5e32f1e6589a.png">


## WAF のログ確認方法
それでは、実際に S3 Select で WAF のログを確認してみましょう。

1. [サービス] > [S3] > [バケット] からログ出力先の S3 にアクセス

1. アクセスを確認したい日時のフォルダに移動して、対象のアクセスログファイルをクリックする
<img width="600" alt="2019-11-25_13h52_12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385681/63142130-8260-0633-1774-031e40dc9c24.png">

1. 上部メニューの [アクション] > [S3 Select] を選択
<img width="600" alt="2019-11-25_13h55_13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385681/67d4f680-64a8-eb1c-8d7b-6b88c72dcf91.png">

1. 以下を選択し、[次へ] をクリック
    ファイル形式 : JSON
    JSONタイプ : JSON 行
    圧縮 : GZIP (Kinesis 側の設定によって変わります)
<img width="600" alt="2019-11-25_14h02_25.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385681/cc340842-ac73-ebb6-2ff7-b68bfd6e2337.png">

1. [SQL 式]のダイアログボックスに以下を入力し、[SQL の実行]を選択

- 許可されたアクセスログを確認

```sql
select * from S3Object s where  s."action" = 'ALLOW'
```
JSON データの `"action" : 'ALLOW'` となっているログが表示される
<img width="600" alt="2019-11-25_14h32_55.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385681/4e822ca0-182e-aa2b-5ee7-98a15c1275e0.png">

- 拒否されたアクセスログを確認

```sql
select * from S3Object s where  s."action" = 'BLOCK'
```
`"action" : 'BLOCK'`となっているログが表示される
<img width="600" alt="2019-11-25_15h00_38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/385681/e1dae3e8-c5a4-094f-f78c-0e5442289f19.png">


WAF によってアクセスがブロックされたログが確認できました！
上記画像だとログが全部表示できていませんが、ログの例が AWS ドキュメントで記載されています。

```json
{
			
	"timestamp":1533689070589,                            
	"formatVersion":1,                                   
	"webaclId":"385cb038-3a6f-4f2f-ac64-09ab912af590",  
	"terminatingRuleId":"Default_Action",                
	"terminatingRuleType":"REGULAR",                     
	"action":"ALLOW",                                    
	"httpSourceName":"CF",                               
	"httpSourceId":"i-123",                             
	"ruleGroupList":[                                    
                         {  
                          "ruleGroupId":"41f4eb08-4e1b-2985-92b5-e8abf434fad3",
                          "terminatingRule":null,    
                          "nonTerminatingMatchingRules":[                  
                                                         {"action" : "COUNT",   
                                                         "ruleId" : "4659b169-2083-4a91-bbd4-08851a9aaf74"}       
                                                        ]
                          "excludedRules":              [
                                                         {"exclusionType" : "EXCLUDED_AS_COUNT",   
                                                          "ruleId" : "5432a230-0113-5b83-bbb2-89375c5bfa98"}
                                                        ]                          
                         }
                        ],
     
	"rateBasedRuleList":[                                 
                             {  
                              "rateBasedRuleId":"7c968ef6-32ec-4fee-96cc-51198e412e7f",   
                              "limitKey":"IP",
                              "maxRateAllowed":100                                                                                           
                             },
                             {  
                              "rateBasedRuleId":"462b169-2083-4a93-bbd4-08851a9aaf30",
                              "limitKey":"IP",
                              "maxRateAllowed":100
                              }
                              ],
			
	"nonTerminatingMatchingRules":[                                
                                       {"action" : "COUNT",                                                           
                                       "ruleId" : "4659b181-2011-4a91-bbd4-08851a9aaf52"}    
                                      ],
                                  
	"httpRequest":{                                                             
                       "clientIp":"192.10.23.23",                                           
                       "country":"US",                                                         
                       "headers":[                                                                 
                                   {  
                                    "name":"Host",
                                    "value":"127.0.0.1:1989"
                                   },
                                   {  
                                    "name":"User-Agent",
                                    "value":"curl/7.51.2"
                                   },
                                   {  
                                    "name":"Accept",
                                    "value":"*/*"
                                   }
                                 ],
                      "uri":"REDACTED",                                                
                      "args":"usernam=abc",                                         
                      "httpVersion":"HTTP/1.1",
                      "httpMethod":"GET",
                      "requestId":"cloud front Request id"                    
                      }
}

```

ログの読み方についても、以下の AWS ドキュメントで説明されています。

>以下ではこれらのログに示されている各項目について説明しています。
**timestamp**
タイムスタンプ (ミリ秒単位)。
**formatVersion**
ログの形式バージョン。
**webaclId**
ウェブ ACL の GUID。...
[ウェブ ACL トラフィック情報のログ記録 - AWS WAF、AWS Firewall Manager、および AWS Shield アドバンスド](https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/logging.html)

## 補足
AWS ドキュメントを参考にしながらログの中身を見ていくと、WAFのどのルールでブロックされたか確認できる箇所があることが分かります。

>**ruleGroupList**
このリクエストで動作したルールグループのリスト。前述のコード例では、1 つのみです。

WAF で設定しているルールの中で、拒否されたアクセスがどのルールでブロックされたか確認する場合があると思いますが、その際は以下のように検索すればブロックされたルールの ID が確認できます。

```
select * from S3Object s where  s."action" = 'BLOCK'
select * from S3Object[*].ruleGroupList
```

↓`terminatingRule` の `ruleId` にブロックされたルールの ID が表示されています。

```json
    {
        "_1": [
            {
                "ruleGroupId": "7c968ef6-32ec-4fee-96cc-51198e412e7f",
                "terminatingRule": {
                    "ruleId": "462b169-2083-4a93-bbd4-08851a9aaf30",
                    "action": "BLOCK"
                },
                "nonTerminatingMatchingRules": [],
                "excludedRules": null
            }
        ]
    }
```

## 参考ドキュメント
- AWS WAF ドキュメント
https://docs.aws.amazon.com/ja_jp/waf/index.html