はじめに
WAFのルールで Rate-based rule がありますが、これだと**「5分間に同じIPから設定した回数を超えたリクエスト」でしかブロックができません。
これで十分なら良いのですが、ちゃんと設定値を考えないと場合によったら正常なアクセスに対してもブロックしてしまうかもしれないです。
そこで、「同じIPからのリクエストかつ、指定のエラーコードが設定した回数を超えた場合にブロック」**をしたい場合の設定を行います。
内容としてはAWS公式ドキュメントにある「チュートリアル: 不正なリクエストを送信する IP アドレスのブロック」になります。
これを自分なりに噛み砕いて解説しました。あとLambdaのプログラムで一部おかしいと思われるところがあったのでそこを修正しています。
概要
システムの流れとしてはまず、
- CloudFrontのアクセスログをS3バケットへ保存します。
- S3イベントからバケットにログが出力されたのをトリガーにLambdaが動きます。
- Lambda処理で1分間に指定したレスポンスコードが閾値を超えたらWAFのIPブロックリストへ登録します。
- LambdaのログをCloudWatchへ出力します。
また、「3.」では一定時間経過した場合IPブロックリストから除外する処理も行われています。デフォルト4時間(14400sec)です。
[注意点]*
チェック自体は1分間に対するレスポンスコード数ですが、CloudFrontのログは1分ごとに出力されるわけではありません。
「ログファイル配信のタイミング」によると 「1 時間に最大で数回配信」を記載があります。また、「最大で 24 時間遅れることもあります」
とも記載されています。
そこまで気にする必要はないと思いますが、頭に入れて置いた方が良いかもです。
スタックの作成
CloudFormationのテンプレートが用意されているのでそれを元に作成します。
今回は東京リージョンで行いますので「アジアパシフィック (東京) でスタックを作成する」をクリックしてスタックを作成してください。
ドキュメントには他に「バージニア」「オレゴン」「アイルランド」のテンプレートも用意されています。
またテンプレートで作成されるのは、
- WAF(ウェブACL、IPセット、ルール)
- S3バケット
- Lambda関数
- IAMロール
になります。
テンプレートの選択
するとCloudFormationのスタック作成画面へ遷移します。
そこで表示される画面ではテンプレート選択がすでにされていることを確認してください。
もし、何も入力されていない場合やリンクからではなく管理コンソールからCloudFormationを新規に作成した場合は以下のURLを入力すればOKです。
https://s3.amazonaws.com/awswaf.ap-northeast-1/block-bad-behaving-ips/block-bad-behaving-ips_template.json
詳細設定
次に、詳細設定になります。ここではCloudFrontアクセスログ出力用のバケットを新規に作成します。
既存のバケットを利用したい場合もまずはここで新規に作成する必要があります。
オプション
ここは何も設定せず全てデフォルトの状態で次へ進みます。
確認
IAMリソースが作成される場合があることを承諾し、作成をクリックします。
とりあえず CREATE_IN_PROGRESS となっている間は色々作成中です。
CREATE_COMPOLETE まで数分かかりますが、完了したらテンプレートでいくつか情報は出力されるようになっているので、出力タブで情報を確認することができます。
RequestThreshold:閾値
CloudFrontAccessLogBucket:CloudFrontアクセスログバケット
AutoBlockIPSetID:Lambdaから追加されるIPセットのID
ManualBlockIPSetID:手動で追加したい場合のIPセットのID
WAFBlockPeriod:ブロックし続ける時間
ウェブACLをCloudFrontへ関連づける
今回のスタックで作成されたウェブACLの名前は Malicious Requesters になります。
CloudFormationのスタックではウェブACLは表示されませんがIPセットから追うとわかります。
このウェブACLを関連付けるには「Rules」タブを選択し、下部にあるAdd association から行うことができます。
Resource選択のポップアップが表示されるので関連付けたいリソースを選択してAddをクリックすれば完了です。
CloudFrontログ用バケットの設定
CloudFrontで出力されるログを先ほどスタックで作成したS3バケットへ保存されるように設定を行います。
以上で設定は完了です。
Lambdaプログラム修正
テストしたところ、プログラムの一部におかしな所があったのでそこを修正します。
137〜139行目あたりにあるif文の処理になります。
if total_diff_sec > (BLACKLIST_BLOCK_PERIOD):
print "[merge_current_blocked_requesters] \t\tExpired BLOCK %s rule"%k
outstanding_requesters['block'][k] = v
if total_diff_sec > (BLACKLIST_BLOCK_PERIOD):
print "[merge_current_blocked_requesters] \t\tExpired BLOCK %s rule"%k
ココ→ else:
outstanding_requesters['block'][k] = v
テスト
以上で設定は完了したので実際にテストしてみます。
サンプルとなるアクセスログファイルをAWS公式ドキュメントからダウンロードし、先ほど指定したS3バケットへアップロードします。
確認
「AWS WAF > IP address > Auto Block Set」を確認します。
サンプルをそのままアップした場合、以下のようにリストに追加されました。
また、S3バケットのルートに current_outstanding_requesters.json というファイルが作成されています。
このファイルでは上の画像のようにIPブロックリストに追加されたIPごとのリクエスト数とリストに追加した日時を確認することができます。
{"block": {"203.0.113.0": {"max_req_per_min": 70, "updated_at": "2019-03-15 04:22:22"}, "198.51.100.0": {"max_req_per_min": 66, "updated_at": "2019-03-15 04:22:22"}, "192.0.2.0": {"max_req_per_min": 53, "updated_at": "2019-03-15 04:22:22"}}}
おわりに
チュートリアルを行なっていて感じるのが、CFnのテンプレートを利用するのはとても便利なのですが、ちゃんと理解しなくても「なんとなく」で出来てしまうのが気をつけないといけないなという点です。
今回、Lambda関数のプログラムに不具合があったおかげで、より理解を深めることができて良かったです。
エラーコードや対象ログバケットなどの変更を行いたい場合についてはこちらをご参照ください。
CloudFrontのアクセスログを使って特定IPからの不正リクエストをAWS WAFでブロックする - 初期設定編