Cloud Armor「事前構成済みルール」を使いこなせ:現場でハマるWAFチューニングの極意
こんにちは、SREの現場で日々パケットと格闘しているエンジニアです。
今日は、GCPの「最後の砦」とも呼ぶべき Cloud Armor、特にその中核をなす「事前構成済みWAFルール」について深掘りします。Web APIを公開していると、深夜のログに 403 Forbidden が溢れ、「正常なリクエストまで弾いているじゃないか!」とPMから呼び出される……そんな経験はありませんか?
教科書的なドキュメントは公式に任せるとして、ここでは「どう設定すれば運用で事故らないか」「ModSecurityの挙動をどう解釈すべきか」という、泥臭い実務の視点でお話しします。
—
1. なぜ「事前構成済みルール」なのか?
Cloud Armorの事前構成済みルールは、オープンソースのWAFエンジンである ModSecurity のコアルールセット(CRS)をGoogleがマネージドサービスとして実装したものです。
SQLインジェクション(SQLi)やクロスサイトスクリプティング(XSS)といった攻撃は、攻撃者が執拗にペイロードを難読化してきます。これらを自前で正規表現を書いて防ごうとするのは、SREにとっての自殺行為です。まずはGoogleが提供する標準ルールを適用し、「検知のみ(Preview mode)」で運用を開始するのが鉄則です。
—
2. 通信フローと評価のタイミング
Cloud Armorは、GCPのグローバルロードバランサー(GLB)のフロントエンドで動作します。パケットの流れは以下の通りです。
1. Client からのリクエストが Global External HTTP(S) Load Balancer に到達。
2. Cloud Armor がリクエストヘッダー、URLパス、クエリパラメータ、そして POST ボディを検査。
3. WAFルール評価: ここで事前に定義した expression にヒットするか判定。
4. Action: allow ならバックエンドへ転送、deny なら 403 を即時返却。
ここで重要なのは、「評価対象の範囲」です。特にPOSTリクエストのボディサイズには制限があり、大きすぎるペイロードは検査がスキップされたり、逆に誤検知の原因になったりします。
—
3. 実践:Cloud Armorルールの適用とチューニング
まずは、特定のルールを適用しつつ、誤検知を回避するための「評価モード(Preview)」設定を見てみましょう。
gcloudコマンドによる設定例
# セキュリティポリシーを作成
gcloud compute security-policies create my-web-policy \
--description="API保護のためのポリシー"
# SQLiとXSSのルールを適用しつつ、まずはプレビューモードでログを確認する
# パラメータ: preview=true にすることで、ブロックせずにログだけを出す
gcloud compute security-policies rules create 1000 \
--security-policy=my-web-policy \
--expression="evaluatePreconfiguredExpr('sqli-stable') || evaluatePreconfiguredExpr('xss-stable')" \
--action=deny-403 \
--preview \
--description="SQLi/XSSの検知テスト"
なぜ preview が重要なのか?
本番環境でいきなり --no-preview を叩くのは、銃の安全装置を外してトリガーを引くようなものです。まずは preview を有効にして、Cloud Loggingで jsonPayload.enforcedSecurityPolicy.outcome が DENY になっているリクエストを丹念に追跡してください。
—
4. 誤検知(False Positive)との戦い方
運用で最も多いのが、「正当なリクエストなのにSQLiとして検知される」ケースです。例えば、ユーザーが入力した長いテキストや、特殊な記号を含むJSONが sqli-stable に引っかかることは珍しくありません。
この場合、「ルールIDを特定して除外する」のがプロのやり方です。
# 特定のルールID(例: 1234567)だけをホワイトリスト化する設定例
gcloud compute security-policies rules update 1000 \
--security-policy=my-web-policy \
--action=deny-403 \
--expression="evaluatePreconfiguredExpr('sqli-stable', ['1234567'])"
このように、evaluatePreconfiguredExpr の第二引数に、除外したいルールIDのリストを渡すことで、特定のシグネチャだけを無効化できます。
—
5. 現場のTips:テスト用ペイロードの投げ方
実際にルールが効いているか確認するために、curlで攻撃シミュレーションを行ってみましょう。
# SQLインジェクションの典型的なパターンを投げてみる
curl -v -X POST "https://api.example.com/search" \
-H "Content-Type: application/json" \
-d '{"query": "SELECT * FROM users WHERE id = 1 OR 1=1"}'
もしCloud Armorが正しく機能していれば、レスポンスコードは 403 になります。
注意点:
curl でテストする際は、必ず --proxy などを経由させず、直接エンドポイントに投げてログを確認してください。また、EXCEEDS-RATE-LIMIT をテストする場合は、短時間に大量のリクエストを投げる必要がありますが、本番環境のバックエンドを落とさないよう注意が必要です。
—
まとめ:SREとして心に刻むべきこと
- デフォルトを盲信しない:
sqli-stableやxss-stableは強力ですが、アプリケーションの特性に合わせて必ずチューニングが必要です。 - ログこそが正義:
Cloud Loggingで「なぜブロックされたか(matchedScoreやruleId)」を特定する癖をつけましょう。 - 段階的適用:
previewモードで1週間ほど様子を見ることが、平穏な夜を過ごすための唯一の道です。
Cloud Armorは、使いこなせばこれ以上ない強力な盾になります。皆さんのサービスが、不当な攻撃から守られ、健やかに稼働し続けることを願っています。
何か具体的なトラブルや、設定値の相談があれば、またいつでも聞いてくださいね。現場からは以上です!
コメント