どうも、大曲です。
今回はGCPのWAF機能を調査して導入したのでそれを共有できれば良いなと思います。
調べた項目
- WAFのルールの模索
どんなルールがあるのか - WAFの結果の可視化
どんな攻撃があったかを把握できる機能はあるか
Google Cloud Armorとは
https://cloud.google.com/armor/
ネットワークのセキュリティ対策(IP制限など)もありますが
今回はWAFとしての機能を導入しました。
WAFのルールの模索
用語
- ポリシー:全体設定を指す(デフォルトのルールも決める)
- ルール:拒否するルール、複数記入して優先度を決める
- ターゲット:適応させるGCPのリソースを決める(WAFの場合はロードバランサバックエンドサービスであるLBが該当する)
設定項目
ポリシー

| 項目 | 説明 |
|---|---|
| ポリシー名 | 作成後は変更できない 名前 に使用できる文字は、小文字、数字、ハイフンのみ |
| デフォルトのアクション | 許可 or 拒否 |
WAFの設定ではデフォルトのアクションは許可にしており、
ルールの方で該当するものを拒否していく設定方法をとっています。
ルールの設定項目

| 項目 | 説明 |
|---|---|
| 条件 | 基本モード:IP アドレスまたは IP 範囲のみ 詳細モード:CEL(Common Expression Language)を使用して、 IP 範囲、国コード、リクエスト ヘッダー、事前設定済みのルール(クロスサイト スクリプティング(xss)、SQL インジェクション、またはこれらの組み合わせが可能 |
| 一致 | CELの内容を記述する |
| アクション | 許可 or 拒否 |
| 拒否ステータス | 403:アクセス拒否 404:ファイル未検出 502:不正なゲートウェイ アクションを拒否した場合に3つが選択できる |
| プレビューのみ | プレビューモードが作動する(実際のリクエストに影響が出ない) |
| 優先度 | 優先度は、0(最高)から 2,147,483,647(最低) 0は設定しないことを勧めます※1 |
※1 理由は躓いた部分で説明
ちなみにルールがエラーの場合は設定更新後に適応処理が実行されますが、そのときにビックリマークが表示されて失敗したことを通知されます。

ルールについて
ルール設定はIPやリクエストパスなどを設定できる他にSQLインジェクションなどの一般的なルールはOSSのOWASP ModSecurity Core Rule Set (CRS)を利用しているようです。
- SQL インジェクション
- クロスサイト スクリプティング
- ローカル・ファイルインクルード(Local file inclusion)
- リモート・ファイルインクルード(Remote file inclusion)
- RCE(Remote code execution)
上記はルールセットがありましたが、「SSRF(Server Side Request Forgery)」は無かったです(AWSにはありました)
比較としてAWS WAF ルール一覧はこちら
参考URL:
Google Cloud Armor カスタムルール言語リファレンス
Google Cloud Armor WAF ルールのチューニング
WAFの結果の可視化
メトリクス
Cloud Monitoringに自動的に「Network Security Policies」というダッシュボードが作成されます。
ただし、自動的に作成されるものは基本的にポリシー単位ですのでロードバランサー単位で見たい場合はカスタムメトリクスで作成することをお勧めします。

リクエストがブロック判定されたメトリクスのクエリは以下の通りです。
fetch network_security_policy
| metric 'networksecurity.googleapis.com/https/request_count'
| filter (metric.blocked == true())
| align rate(1m)
| every 1m
| group_by [metric.backend_target_name],
[value_request_count_aggregate: aggregate(value.request_count)]
リクエスト
Cloud Loggingで1リクエスト単位で確認することができます。
ただし、ログルーターの設定次第では確認出来なくなります。
(例:WAFの拒否ステータスである403にした場合、ログルーター側で403を無視する設定にしているケース)
以下のようなイメージで出力されます。

項目の説明
- enforcedSecurityPolicy=実際のリクエストの状態
- previewSecurityPolicy=プレビューモードの状態
| 項目 | 説明 | 備考 |
|---|---|---|
| priority | 適応されたルール優先度 | 優先度が0の場合は表示されない |
| name | ポリシー名 | |
| configureAction | セキュリティーポリシーで設定されている内容 許可 or 拒否のアクション |
|
| outcome | 実際に処理された結果 許可 or 拒否のアクション |
|
| preconfigureExprIds | 事前に設定されたルールのID(owasp-crs-v030001-id942140-sqli) | カスタムルール(origin.region_code == 'AU'..etc)は表示されない |
configureActionとoutcomeの違いに関して。
configuredActionはセキュリティーポリシーで設定されている内容であり、
outcomeは実際に処理された結果となります。
許可の設定に対して許可された、拒否の設定に対して拒否されたことを示します。
結局、二つは一緒になると思います。
調査で利用したログエクスプローラでのクエリ
- 拒否されたリクエスト
jsonPayload.enforcedSecurityPolicy.outcome="DENY" - プレビューモードでの拒否
jsonPayload.previewSecurityPolicy.outcome="DENY" - ルールからの抜粋
jsonPayload.previewSecurityPolicy.preconfiguredExprIds=~"owasp-crs-v030001-id942420-sqli" - 優先度
jsonPayload.previewSecurityPolicy.priority=2
躓いた部分
ルールの優先度では0を設定したらロギングで表示されない
0にするとCloud LoggingのjsonPayload.previewSecurityPolicyでpriorityが表示されません。
そのため、ルールで設定する優先度は1からにする方が良い。
# ルールの優先度が0の場合はpriorityが欠損する
{
"jsonPayload": {
"enforcedSecurityPolicy": {
"configuredAction": "DENY",
"outcome": "DENY",
"name": "test-waf"
}
}
}
# ルールの優先度を1にすることでpriorityが欠損しない
{
"jsonPayload": {
"enforcedSecurityPolicy": {
"configuredAction": "DENY",
"outcome": "DENY",
"priority": 1,
"name": "test-waf"
}
}
}
モニタリングで利用できる指標でプレビューモードと実際のリクエストの値が一致しない
Previewed Requests (Blocked)+Previewed Requests (Allowed)=Previewed Requests (Total)Previewed Requests (Total)=Requests (Total)
上記の二つの式が成り立つと思っていましたが、違いました。
ルールを以下の二つ設定(一つはプレビューモード)した場合。
#1 Deny (403): OWASP ModSecurity Core Rule Set ← プレビューモード #2 Allow デフォルトのルール
プレビューモードで許可されたルールは無いため、Previewed Requests (Allowed)は増えません。
あくまでプレビューモードかつ許可するアクションであるルールのみがカウントされる仕様のようです。
それぞれの状態でまとめるとこのようになります。
プレビューモードの有無で数値が区別されているようで想定しいたものとは違うメトリクスでした。
| プレビューモード | アクション | カウントされるメトリクス |
|---|---|---|
| あり | 許可 | Previewed Requests (Allowed)Previewed Requests (Total) |
| あり | 拒否 | Previewed Requests (Blocked)Previewed Requests (Total) |
| なし | 許可 | Requests (Allowed)Requests (Total) |
| なし | 拒否 | Requests (Blocked)Requests (Total) |
まとめ
WAFのポリシーの模索
OWASPのルールを活用すると良い(SQLインジェクション..etc)
ただし、誤検知のケースもあるため、プレビューを必ず実施した方が良いWAFの結果の可視化
Cloud Loggingで1リクエスト単位で確認が可能
Cloud Monitoringのメトリクスでで拒否されたリクエスト数などを把握でき、アラートの設定も可能
導入を通して
プレビューモードは非常に優秀
ルールはガチガチにしたいものの本番への影響がどの程度あるかはわかりません。
とりあえずプレビューモードで本番で実行して様子見が一番効率的だと思います。
実際に誤検知していたリクエストもあり、非常に助かりました。ロギングでどのルールが影響したのか把握しやすい
1リクエストごとで細かくデータを追えるので調査する際は非常に楽でした。
WAFの調査は初めてでしたが、色々と確認できて楽しかったです。