こんにちは、SREチームのシニアエンジニアです。
クラウドインフラの規模が拡大するにつれ、セキュリティ要件は厳しさを増します。「単にインターネットに出られる、入れないを制御するだけではなく、ペイロードの中身まで精査し、特定のシグネチャを検知したい」――そんな現場の切実な要望に応えてくれるのが AWS Network Firewall です。
しかし、このマネージドファイアウォール、いざ導入しようとすると多くのエンジニアがその独特なルール評価の仕組み、特に「ステートレス」と「ステートフル」の二段階評価で頭を悩ませます。
「ルールを書いたのにパケットが落ちる」「なぜかステートレスを通ったあとにステートフルでブロックされるんだ?」
そんな現場の泥臭いトラブルシューティングを乗り越えるために、パケットがNetwork Firewallの内部をどう駆け巡り、どう評価されるのか、そのリアルな挙動を徹底的に紐解いていきましょう。
—
AWS Network Firewallの全体像とパケットの旅
まず、AWS Network FirewallがVPCのアーキテクチャの中でどこに位置し、どのようにパケットをハンドリングしているのかをイメージしてください。
Network Firewallは、VPC内の専用サブネット(ファイアウォール用サブネット)に配置されたエンドポイント(ENI)として存在します。ルートテーブルの経路を巧妙にこのENIに向けることで、インターネットゲートウェイ(IGW)やNATゲートウェイ、あるいはVPCピアリングを通過するトラフィックを強制的に検査させます。
パケットがこのファイアウォールENIに到達した瞬間、以下の壮大な旅が始まります。
[パケット到着]
│
▼
┌─────────────────────────────────────────┐
│ ステートレスルールエンジン (Stateless) │
│ - 5タプル(IP, ポート, プロトコル)で評価 │
│ - 優先度(Priority)順に走査 │
└─────────────────────────────────────────┘
│
├── [一致 & Pass/Drop] ──► 即座に処理 (ステートフルへ行かない場合あり)
└── [一致なし / Forward] ──┐
│
▼
┌─────────────────────────────────────────┐
│ ステートフルルールエンジン (Stateful) │
│ - Suricata互換エンジン │
│ - L7ペイロード、ステート(接続状態)を検査 │
└─────────────────────────────────────────┘
│
├── [Alert / Pass / Drop]
▼
[宛先へ転送 or 破棄]
このフローを理解していないと、「ステートレスで Forward したつもりが、ステートフルで想定外のルールに引っかかった」といった事故を引き起こします。それぞれのエンジンの評価順序とアクションの優先順位を深く掘り下げていきましょう。
—
ステートレスルール(Stateless Rules)の評価フロー
ステートレスルールは、その名の通り「接続の状態(ステート)」を保持しません。入ってきた個々のパケットを独立して、主に5タプル(送信元IP、宛先IP、送信元ポート、宛先ポート、プロトコル)に基づいて高速に評価します。
評価順序の鉄則
ステートレスルールグループには、それぞれ優先度(Priority)を割り当てます。
1. 数値が小さい(優先度が高い)ものから順に評価されます。
2. 最初にマッチしたルールのアクションが即座に適用され、それ以降のステートレスルールは評価されません。
3. もしどのステートレスルールにもマッチしなかった場合、デフォルトのアクション(通常はステートフルエンジンへ転送する aws:forward_to_stateful_inspection)が適用されます。
ステートレスアクションの種類
ステートレスルールで指定できるアクションは以下の3つです。
aws:pass: パケットを検査せずにそのまま通過させます(ステートフルエンジンもバイパスします)。aws:drop: パケットを即座に破棄します。aws:forward_to_stateful_inspection: パケットを次の関門であるステートフルエンジンに送ります。
> SREの現場Tips:
> 「とりあえず安全のために全部ステートフルで見たい」という場合は、ステートレスのデフォルトアクションを aws:forward_to_stateful_inspection に設定し、特定の管理用IPなど超高信頼なトラフィックだけを aws:pass でバイパスさせる、という設計が王道です。
—
ステートフルルール(Stateful Rules)の評価フローとSuricataの魔力
ステートレスの網をかいくぐった(あるいはフォワードされた)パケットがたどり着くのが、ステートフルルールエンジンです。ここは内部にオープンソースのIDS/IPSエンジンである Suricata を内蔵しており、パケットのペイロード(L7)やTCPのコネクション状態を完全に把握しながら高度な検査を行います。
評価順序の複雑さと優先順位
ステートフルルールは、単に記述した順番で評価されるわけではありません。ここがAWS Network Firewallで最もハマりやすいポイントです。
ステートフルルールグループには、大きく分けて以下の記述方式があります。
1. Suricata互換ルール(Suricata compatible rules): カスタムのSuricataルール文字列を直接書く方法。
2. 5タプルパケットフィルター(5-tuple rules): AWSマネージドコンソール等で直感的に設定できるルール。
これらが混在する場合、AWS Network Firewallは内部で次のような優先順位(Evaluation Order)に従って評価します。
1. Drop ルール: パケットを破棄するルールが最優先で評価されます。
2. Alert ルール: アラートを生成するルールが評価されます(トラフィックはブロックされません)。
3. Pass ルール: 通信を許可するルールが評価されます。
さらに、Suricataエンジン自体の挙動として、暗黙のデフォルトアクションが存在します。もしどのステートフルルールにもマッチしなかった場合、トラフィックはデフォルトで「許可(Pass)」されます(※ステートフルルールのデフォルト設定に依存します)。
—
実践:AWS CLIによるルールグループの構築と設定例
それでは、実務で使える具体的な設定を見ていきましょう。ここでは、特定のWeb APIサーバー(例: 10.0.1.10)に対して、特定の悪意あるシグネチャや外部からの不正なアクセスをブロックするシナリオを想定します。
以下のAWS CLIコマンドは、ステートレスおよびステートフルルールを含むファイアウォールポリシーを作成する一例です。
# 1. ステートレスルールグループの作成
# 目的: メンテナンス用踏み台からのSSH(Port 22)はステートフル検査をスキップして即座にPassする
aws network-firewall create-rule-group \
--rule-group-name "stateless-bypass-ssh" \
--rule-group '{
"RuleVariables": {
"IPSets": {
"HOME_NET": { "Definition": ["10.0.0.0/16"] }
}
},
"StatelessRulesAndCustomActions": {
"StatelessRules": [
{
"Priority": 10,
"RuleDefinition": {
"MatchAttributes": {
"Sources": [{"AddressDefinition": "192.0.2.50/32"}],
"DestinationPorts": [{"FromPort": 22, "ToPort": 22}],
"Protocols": [6]
},
"Actions": ["aws:pass"]
}
}
]
}
}' \
--type STATELESS \
--capacity 100 \
--region ap-northeast-1
# 2. ステートフルルールグループの作成(Suricata互換ルール)
# 目的: 外部への不正なHTTP通信(例: 既知のマルウェアC2サーバーへの通信パターン)を検知・ドロップする
aws network-firewall create-rule-group \
--rule-group-name "stateful-suricata-malware-block" \
--rule-group '{
"RulesSource": {
"RulesString": "drop tcp $HOME_NET any -> $EXTERNAL_NET 80 (msg:\"ET MALWARE Suspicious HTTP POST detected\"; content:\"/bad-path/upload\"; sid:1000001; rev:1;)"
}
}' \
--type STATEFUL \
--capacity 100 \
--region ap-northeast-1
Suricataルールの読み解き
上記の RulesString で指定したSuricataルールは、ネットワークセキュリティの現場で非常に強力な武器になります。
drop tcp: 条件に合致したTCPパケットをドロップする。$HOME_NET any -> $EXTERNAL_NET 80: 内部ネットワークの任意のポートから、外部ネットワークのポート80(HTTP)へ向かう通信が対象。content:"/bad-path/upload": HTTPリクエストのペイロード内に指定した文字列が含まれているかを検査する(L7インスペクションの真骨頂です)。sid:1000001: ルール固有のシグネチャID。ログ解析やアラート監視の際にこのIDがCloudWatch Logsに出力されます。
—
デバッグとトラブルシューティングの極意
「設定は入れたのに、APIクライアントからのリクエストがタイムアウトする……」
そんな修羅場でSREが最初に行うべきデバッグ手順を共有します。
1. CloudWatch Logsの有効化(ログ出力の設定)
AWS Network Firewallは、パケットの検査結果をAmazon CloudWatch LogsやAmazon S3に流すことができます。特に Alert ログと Flow ログを有効にすることは、インフラ構築の絶対条件です。
次のように、ファイアウォールログの出力先を設定します。
# ログ設定の適用(AlertとFlowをCloudWatch Logsへ出力)
aws network-firewall update-logging-configuration \
--firewall-name "production-edge-firewall" \
--logging-configuration '{
"LogDestinationConfigs": [
{
"LogDestinationType": "CloudWatchLogs",
"LogDestination": {
"logGroup": "/aws/network-firewall/prod-cluster"
},
"LogType": "ALERT"
},
{
"LogDestinationType": "CloudWatchLogs",
"LogDestination": {
"logGroup": "/aws/network-firewall/prod-cluster"
},
"LogType": "FLOW"
}
]
}' \
--region ap-northeast-1
2. ログから原因を特定する
CloudWatch Logsに流れてきたログを確認し、どのルール(sid)にヒットしてパケットがドロップされたのかを突き止めます。
もし意図しないパケットが落ちている場合、多くは以下の原因のいずれかです。
- ステートレスでのデッドエンド: ステートレスルールのデフォルトアクションが
aws:dropになっており、必要なトラフィックをaws:forward_to_stateful_inspectionやaws:passするルールを書き忘れていた。 - Suricataの方向指定ミス(
->と<>):HOME_NETとEXTERNAL_NETの向きが逆になっており、レスポンスパケットが想定通りに評価されていない。 - キャパシティ(Capacity)不足: ルールグループ作成時に指定したキャパシティの上限を超えてしまい、ルールが正しくロードされていない(AWS CLIやマネージドコンソールでエラーが出ます)。
—
まとめ
AWS Network Firewallのステートレスおよびステートフルルールの評価順序は、一見すると複雑に入り組んでいるように見えます。しかし、「まず高速な5タプルで大まかに仕分け(ステートレス)、次にL7層やステートを伴う深い検査を行う(ステートフル)」という原則を頭に叩き込んでおけば、怖くありません。
実務においては、まずは最小限のルールからスタートし、CloudWatch Logsでトラフィックの流れた跡を丹念に追いかけながら、段階的にルールをチューニングしていくアプローチが最も確実です。
ネットワークのパケットパズルを解き明かす爽快感を味わいながら、セキュアで堅牢なクラウドインフラを作り上げていきましょう。現場からは以上です!
コメント