【実務・中級編】 Cloud Armorのセキュリティポリシーにおける事前構成済みWAFルール(ModSecurityベース) – クラウドインフラと仮想化ネットワーク実践ガイド

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は、使いこなせばこれ以上ない強力な盾になります。皆さんのサービスが、不当な攻撃から守られ、健やかに稼働し続けることを願っています。

何か具体的なトラブルや、設定値の相談があれば、またいつでも聞いてくださいね。現場からは以上です!

コメント

タイトルとURLをコピーしました