AWS Network Firewallを本番導入で失敗した話と実装のコツ
Network Firewallの設計で実際にハマった落とし穴。AZ間の冗長化ミスから、IDS統合の癖、コスト最適化までの6ヶ月の経験談です。
AWS Network Firewall設計で学んだ実装トラブルと運用のコツ
うちのチームが先月、本番環境のNetwork Firewallを導入してから半年が経った。正直、最初は「AWS管理型なら簡単だろう」と舐めてました。実際に運用してみると、アーキテクチャ設計の落とし穴、IDS統合時の癖、そしてコスト最適化との戦いが続いています。今日は、その過程で学んだ実装のコツと、やってはいけないことを共有したいと思います。
Network Firewallを導入したきっかけ
去年の秋、セキュリティ監査で「ネットワークレイヤーの可視化が足りない」と指摘されたんです。うちのVPCは複数のAZに分散していて、NAT Gatewayを通るトラフィックは把握できるけど、VPC内のマイクロサービス間の通信は完全にブラックボックスだった。
そこで検討したのがNetwork Firewallです。従来のセキュリティグループやNACLと違って、ステートフル検査とIDS/IPS機能がネイティブに組み込まれている。何より、AWS側で管理されるから、パッチ当てや機能追加が勝手に行われる。これは大きい。
ただし、「AWS管理型 = 導入したら終わり」ではなかった。むしろ逆です。
アーキテクチャ設計で最初にハマったこと
最初は以下のような単純な構成を考えてました。
Internet → IGW → Network Firewall → VPC(AZ-1, AZ-2)
素人的には「Firewallを入口に置いとけばいい」と思ってたんですが、実際には大間違いでした。
問題1: AZ間の高可用性を考えてなかった
Network Firewallは、AZ単位でデプロイする必要があります。複数AZで構成しても、各AZのサブネットが異なるIGWを通ると、Firewallをスキップされるリスクがある。
うちのチームが実装したのはこういう構成です:
graph TB
subgraph "Internet"
IGW["Internet Gateway"]
end
subgraph "Network Firewall Layer"
NFW1["Network Firewall<br/>AZ-1a"]
NFW2["Network Firewall<br/>AZ-1b"]
end
subgraph "VPC (10.0.0.0/16)"
subgraph "AZ-1a"
PubSub1["Public Subnet<br/>10.0.1.0/24"]
AppSub1["App Subnet<br/>10.0.10.0/24"]
DBSub1["DB Subnet<br/>10.0.20.0/24"]
end
subgraph "AZ-1b"
PubSub2["Public Subnet<br/>10.0.2.0/24"]
AppSub2["App Subnet<br/>10.0.11.0/24"]
DBSub2["DB Subnet<br/>10.0.21.0/24"]
end
end
IGW -->|Route to NFW| NFW1
IGW -->|Route to NFW| NFW2
NFW1 -->|Inspect| PubSub1
NFW1 -->|Inspect| AppSub1
NFW1 -->|Inspect| DBSub1
NFW2 -->|Inspect| PubSub2
NFW2 -->|Inspect| AppSub2
NFW2 -->|Inspect| DBSub2
AppSub1 ---|"VPC Peering<br/>Route via NFW?"| AppSub2
DBSub1 ---|"East-West<br/>不検査!"| DBSub2
この図の問題が分かりますか?AZ-1aのDBが、AZ-1bのDBと通信するとき、Network Firewallを通らないんです。East-West Trafficが完全にスキップされてる。
最初の実装では、Central Firewallアプローチで「すべてのトラフィックを中央の検査ポイント通す」を目指してたんですが、VPC内通信の場合、それが困難だということに気づきました。
問題2: ルーティングループの危険性
Network Firewallの前に、トランジットゲートウェイ(TGW)を置いて「全トラフィックを集約する」という設計も検討しました。でも、これもうっかりするとループします。
実際、初期実装時に、某開発環境でこれが発生しました:
VPC-A → TGW → Network Firewall → TGW → VPC-A... (ループ)
IAM権限で許可していたため、本番直前にテストで発見できました。危ない。
対策: Network Firewallが配置されるのは「Firewall Subnet」と呼ぶ専用サブネットで、そこに入ってくるトラフィックは 二度とTGWに返さない ルーティングにしました。
IDS統合でぶつかった落とし穴
Network Firewallは独自のルールエンジンを持ってますが、より詳細な脅威検知には、Suricataベースのルールセットが使えます。AWS側で管理されるルールも用意されてます。
ただし、本番運用で「IDS検知が多すぎる」という別の問題が発生しました。
アラートの嵐をいかに整理するか
デフォルトルールセットを有効にすると、毎日1万件以上のアラートが出ます。Slack通知設定してた当初は、Slackが埋もれて、本当に重要な脅威を見落としてました。
[2026-04-15 10:34] 🚨 Trojan.Generic detected
[2026-04-15 10:35] ⚠️ Suspicious DNS query
[2026-04-15 10:36] ⚠️ Unusual port scan
... 9997件省略
これではダメだと思って、CloudWatch Logsで条件フィルタリング設定を強化しました。
実装例:
{
"MetricTransformations": [
{
"MetricName": "CriticalThreat",
"MetricValue": "1",
"DefaultValue": 0,
"MetricNamespace": "NetworkFirewall"
}
],
"LogGroupName": "/aws/networkfirewall/alert",
"FilterPattern": "[... action \"alert\", ... severity = 1 || severity = 2 ]"
}
重大度(Severity)で1, 2だけフィルタして、メトリクスに送るようにしました。その後、低優先度のルールはそもそも無効化しました。
| 重大度 | レベル | 対応時間 | 具体例 |
|---|---|---|---|
| 1 | Critical | 即座 | Ransomware, RCE, Exploitation攻撃 |
| 2 | High | 1時間以内 | SQL Injection, XSS試行 |
| 3以下 | Low | ログのみ | アノマリ検知(ホワイトリスト除外) |
この体制に切り替えてから、誤検知対応の時間が 70% 削減されました。正直、ここが本当に大事だなと実感した部分ですね。
ホワイトリスト管理の工夫
セキュリティとビジネス要件は相反することが多い。特に、「某SaaSサービスへのAPI呼び出し」がIDS検知に引っかかる問題が出ました。
当該ルールを丸ごと無効化するのはリスク高いので、うちのチームは アドレスグループ を使ってきめ細かく除外しました:
# CloudFormation/CDKで管理
from aws_cdk import aws_networkfirewall as nfw
address_group = nfw.CfnAddressGroup(
self, "TrustedSaaS",
capacity=100,
tags=[{"key": "Name", "value": "trusted-api-ips"}]
)
# Rule Groupで参照
rule_definition = nfw.CfnRuleGroup.RuleGroupDefinitionProperty(
stateful_rule_options={
"rule_order": "STRICT_ORDER"
},
stateful_rules=[
nfw.CfnRuleGroup.StatefulRuleProperty(
action="PASS",
header=nfw.CfnRuleGroup.RuleHeaderProperty(
protocol="TCP",
destination="$TRUSTED_SAAS_IPS",
destination_port="443",
direction="ANY",
source="10.0.0.0/16",
source_port="ANY"
),
rule_options=[
{
"keyword": "sid",
"settings": ["1000001"]
}
]
)
]
)
ポイント: アドレスグループは動的に更新できるので、SaaSプロバイダのIPが変わっても、Lambda + EventBridge で自動更新するようにしました。管理の手間が減ったし、ミスも減りました。
実運用で見えたコスト最適化のツボ
Network Firewallは、処理するトラフィック量 と 検査ルール数 に応じて課金されます。
初月の請求を見て、チーム全員で絶句しました。
処理量: 500GB × $0.65/GB = $325
ルール: 5,000 rules × $0.01/rule/day × 30day = $1,500
合計: $1,825/月
これは予想の3倍でした。
トラフィック量削減戦略
すべてのトラフィックをNetwork Firewallに通すのではなく、信頼できるサブネット間はスキップ する戦略を取りました。
例えば、内部通信のうち:
- RDS(DB層)への接続 → DB Security Groupで十分なので、Firewallをスキップ
- ElastiCache → App間 → 同一VPC、内部通信なので除外
- CloudFront → ALB → CloudFront IPレンジはホワイトリスト化
# ルーティングテーブルで条件分岐
route_table_for_db = ec2.RouteTable(self, "DBRouteTable",
vpc=vpc
)
# DB通信は Firewall をスキップ
route_table_for_db.add_route(
"RouteToPrivateSubnet",
destination_cidr_block="10.0.20.0/24",
gateway=local_gateway # VPC Local
)
route_table_for_app = ec2.RouteTable(self, "AppRouteTable",
vpc=vpc
)
# App通信は Firewall 経由
route_table_for_app.add_route(
"RouteToDatabase",
destination_cidr_block="10.0.20.0/24",
gateway=firewall_gateway
)
結果: トラフィック量を約 40% 削減。月$1,300 → $780に減ったのは大きい。
ルール最適化:不要ルールの刈り込み
5,000ルールって、正直ほぼ使ってないルールが大半でした。
セキュリティチームと相談して、以下の判定基準でルール削減を実施:
# 過去30日間で1回も検知されたことがないルール → 候補
# ただし以下は除外:
# - CIS Benchmarkで推奨される基本ルール
# - PCI-DSS対応に必須なルール
# - Compliance Framework で指定されたルール
rules_to_remove = []
for rule in all_rules:
if rule.triggered_count == 0 and rule.category not in MUST_HAVE_CATEGORIES:
rules_to_remove.append(rule.id)
# 段階的に削除(本番環境だから慎重に)
for batch in chunks(rules_to_remove, 100):
remove_rules_from_firewall(batch)
wait_and_monitor(hours=24) # 24時間様子見
最終的に、3,000ルール → 1,500ルールに削減。月$1,500 → $750。
アラート・ロギングの工夫
Network Firewallのアラートを何もしないで溜めておくと、ログだけで毎月テラバイト単位のストレージが消費されます。
うちのチームでは、段階的なログフィルタリング戦略 を取ってます:
xychart-beta
title "Network Firewall ログ保持戦略(月間推移)"
x-axis [Week1, Week2, Week3, Week4, Month]
y-axis "ログ保持期間(日)" 0 --> 90
line [90, 60, 30, 14, 3]
具体的には:
- リアルタイム(0-3日): CloudWatch Logs(即座な脅威検知)
- 短期(3-30日): S3 Standard(調査・フォレンジック)
- 長期(30-90日): S3 Glacier(コンプライアンス保持)
実装の工夫:
from aws_cdk import aws_logs as logs
from aws_cdk import aws_s3 as s3
log_group = logs.LogGroup(self, "NFWLogs",
retention=logs.RetentionDays.THREE_DAYS,
log_group_name="/aws/networkfirewall/alert"
)
# S3へのエクスポート(Kinesis Firehose経由)
firehose_delivery_stream = kinesisfirehose.DeliveryStream(
self, "NFWToS3",
source=kinesisfirehose.StreamSource.cloud_watch_logs(
log_group=log_group
),
destinations=[kinesisfirehose.Destination.s3(
bucket=s3.Bucket(self, "NFWLogs"),
data_format_conversion_props={
"enabled": True,
"input_format": "JSON",
"output_format": "PARQUET"
}
)]
)
効果: ストレージコスト 60% 削減(約$400/月の削減)
まとめ
AWS Network Firewallを本番導入して半年。学んだことは、「マネージドサービスだから簡単」という過信は禁物ということです。むしろ、ネットワーク設計、IDS運用、コスト最適化の3つのバランスを取ることが、本当の難しさなんだと感じました。
正直、この3つが揃わないと、セキュリティを高めるどころか、システムが不安定になったりコストがオーバーヒートしたりするんですよね。
次のアクション:
- アーキテクチャ: East-West Trafficの検査方針を明確化する(全検査 vs 除外ホワイトリスト)
- IDS運用: 重大度レベルでフィルタ、継続的なルール見直し(月1回は削減候補をチェック)
- コスト: トラフィック分散&ルール圧縮で、初期の 40-50% 削減を目指す
- ロギング: 保持期間の階層化で、今月さらに $200/月の削減予定
Network Firewallは確かに強力ですが、「導入」ではなく「運用」がすべてだと痛感してます。同じく導入検討中なら、セキュリティチームだけでなく、インフラチームも早めに巻き込んで、設計フェーズから議論することをお勧めします。失敗事例から学べるのは、本当に幸運だと思うので、この記事が少しでも参考になれば幸いです。