初めに
こんにちは。SRE の izzii です。 テックタッチで AWS WAF を導入した手順を備忘録がてら記述したいと思います。 一応自分は元々 WAF を売る側の人間だったので、 流儀はあるかもしれませんが、参考になるのではないかと自負しています😀
注意
本記事において、 テックタッチのセキュリティ構成については、詳細を明かさないように記述しています。 なのであくまで手順の紹介であり、事例の紹介というレベルの解像度ではありません。
導入の背景
以前からテックタッチのバックエンドサーバーには、AWS WAF Classic が適用されていました。 AWS WAF Classic とは古いバージョンの AWS WAF です。 元 WAF 屋さんだった自分の入社に伴って、最新の AWS WAF に入れ替えつつ、シグネチャや運用を整理することにしました。 (そういう意味では「再」導入と呼べるかもしれません。)
ルールの選定
WAF のルールとは、正常なアクセスと不正なアクセスを区別するためのロジックのことです。 AWS WAF は初期状態ではルールが空っぽなので投入するルールを選定する必要があります。 AWS WAF で使えるルールは大きく4パターンです。
AWS の用意しているマネージドルールセット(AMR)
一部を除いて、無償で使えます。 https://docs.aws.amazon.com/ja_jp/waf/latest/developerguide/aws-managed-rule-groups-list.html
様々な種類があるので、ご自身の環境に合わせてルールをピックしましょう。 その中でも、 コアルールセット が網羅性の高いルールセットになります。
サードパーティベンダーのマネージドルールセット(有償)
https://aws.amazon.com/marketplace/solutions/security/waf-managed-rules
本気で選定しようとするなら、実アクセスに対して、ルールの正解率と再現率を比較していくのが一番だと思います。正解率、再現率とはルールが不正なアクセスを正しく検出しつつ、正常なアクセスは正しく無視するといった性能の指標です。無償のルールに比べると性能は高い傾向があります。
マネージドサービスに付随するルール
WafCharm のようなサービスに任せるという手段です。 https://www.wafcharm.com/
カスタムルール
自作ルールを利用できます。ただしフルスクラッチで作るというよりは、 他のありもののルールと併用するのが一般的でしょう。
エージング
エージング(aging)とは慣らし作業のことです。 防御力を担保しつつ、ビジネスに悪影響の出ない WAF に調整していきます。
観測用の WAF を実環境に適用する
ルール選定で AMR を利用することを選択したと仮定します。
まずは Web ACL にマネージドルールを登録します。コンソールから簡単に有効にできます。この段階から Firewall Manager を使う必要はないかと思います。
マネージドルールの全てのルールアクションを COUNT にします。アクションが COUNT だと検知はしても遮断はしない状態になります。
Web ACL を ALB や CloudFont といったリソースにアタッチします。するとリソースで WAF を有効にすることが可能になります。アタッチするリソースと Web ACL の種類に違いがあるのですが詳細は割愛します。
AWS WAF にルールを適用することで通信速度に影響が出る可能性はあります。ただし私は気がつけるほどの影響を感じた経験がありません。
ログを観測分析する
Web ACL の logging を設定します。 その際に Filter を設定することで、検出したアクセスのみを抽出するようにできます。コストが浮くのでオススメです。
ただし、コンソール上からは見えない設定が存在していて、CUI から弄らないと想定通りの抽出ができないというハマりどころがあります。クラメソ先生の記事が助けてくれることでしょう。
https://dev.classmethod.jp/articles/aws-waf-counted-log-filtering/
分析の方法は十人十色でしょう。ただし、Athena のような SQL ライクなインタフェースで分析するのはシンドイと思います。ログのフォーマットが複雑なためです。自分は jupyter notebook (Python) で分析しました。
ルールの調整
分析結果を元に、AWS WAF のラベル機能を用いてルールのアクションを特定のパスにおいてのみ COUNT に調整する方法を説明します。特定のルールのシグネチャそのものに手を入れることは説明しません。
ルールのアクションを変更する
誤検知がないと考えられ、有効にしたいルールのアクションは BLOCK としましょう。(GUI では、COUNT を無効にすることで BLOCK となります。)
また特定のパスでのみ COUNT にしたいルールは COUNT にておきます。
ラベルを利用して特定のパターンのみ COUNT とする
対象のルールが入ったルールグループよりも後段で、対象のルールのラベルを利用して除外ルールを作成します。
具体的には、以下の JSON がラベルによる除外のルールです。
{ "Name": "CUSTOMIZED_RULE1", "Priority": 0, "Statement": { "AndStatement": { "Statements": [ { "NotStatement": { "Statement": { "RegexMatchStatement": { "RegexString": "^/x/y/z/", "FieldToMatch": { "UriPath": {} }, "TextTransformations": [ { "Priority": 0, "Type": "NONE" } ] } } } }, { "OrStatement": { "Statements": [ { "LabelMatchStatement": { "Scope": "LABEL", "Key": "awswaf:managed:aws:core-rule-set:SizeRestrictions_QueryString" } }, { "LabelMatchStatement": { "Scope": "LABEL", "Key": "awswaf:managed:aws:core-rule-set:SizeRestrictions_CoookieHeader" } } ] } } ] } }, "Action": { "Block": {} }, "VisibilityConfig": { "SampledRequestsEnabled": true, "CloudWatchMetricsEnabled": false, "MetricName": "CUSTOMIZED_RULE1" } }
上の例は、
/x/y/z/*
以外へのアクセスSizeRestrictions_CoookieHeader
またはSizeRestrictions_QueryString
に検知
の場合に BLOCK するというルールです。これによって特定の URI パターン、特定のルールのみアクションを COUNT とすることができます。
デプロイ
実運用には Firewall Manager を使いました。目的は、
- 開発、ステージング、本番全ての環境で共通の構成を当てたい
- アジャイルなサイクルで更新したい
という2つの要件を満たすためです。前者の理由だけであれば CloudFormation テンプレート だけで適うかもしれませんが、セキュリティ構成の更新をコードによる管理サイクルとは別に GUI でアジャイルに管理したいためです。
例えば、2021年末に log4j が流行した時のように、日々 WAF による適切防御方法がコロコロと変わるときや、WAF が誤検知を引き起こしてお客様の利用を阻害してしまったときに、コンソールを利用した方が、早く正しく構成の変更が行えると考えました。
Edit scope Policy という設定から、 Firewall Manager で作った雛形の WebACL を適用するリソースを指定できます。
併せて、監視の仕組みも同時に設定することをお勧めします。
「5分間当たりのリクエスト遮断数、攻撃検知数」といった、メトリクスベースでアラートを発報する仕組みを整えておけば、誤検知が起きた時や、攻撃キャンペーンのターゲットになった場合に気がつくことができるでしょう。
AWS WAF のようなプロキシ型の WAF の場合、遮断されたアクセスについては一般的に、ボディデータはログに保存されないことには注意しましょう。ボディによる検知が、どこで引き起こされたかを知るには、少々手間がかかるのが一般的です。
最後に
テックタッチが、 AWS WAF をテックタッチに再導入した手順の紹介でした。セキュリティの観点で色々曖昧にしているので、事例とまではいかない説明ではありますが、全体的な流れが参考になれば幸いです。「WAF が必要かよくわからない」という状況でも、一旦観測用の WAF を仕込んで、どんな攻撃が来ているか分析してみるというのも、気軽に使える AWS WAF なら悪くない使い方だと思います。