「パケットは嘘をつかない。だが、パケットそのものを見る前に、僕らには見るべき『足跡』がある。」
現場で数々のネットワークトラブルを叩き伏せてきたエンジニアなら、この言葉の意味が痛いほどわかるはずだ。AWSという広大な仮想ネットワークの海で、ある日突然「APIのリクエストがタイムアウトする」「特定のクライアントからだけ接続できない」といった事態に直面したとき、僕たちの唯一の羅針盤となるのが VPC Flow Logs(VPC フローログ) だ。
今日は、教科書的な説明は抜きにして、実務で本当に役立つ「VPCフローログの進化と、そのログフォーマットが持つ真の価値」について、ディープに解説していこう。
—
1. VPCフローログは「監視カメラ」である
VPCフローログは、ENI(Elastic Network Interface)を通過するIPトラフィックのメタデータをキャプチャする機能だ。よく勘違いされるが、これはパケットキャプチャ(PCAP)ではない。パケットの中身(ペイロード)は見せない。代わりに、「誰が、どこへ、いつ、どのプロトコルで、どれだけのデータを送ったか、そしてそれは許可されたのか拒否されたのか」という通信の要約を記録する。
いわば、ホテルの廊下に設置された監視カメラのようなものだ。部屋の中で何が話されているか(データ内容)は分からないが、誰がどの部屋に入り、何分滞在したかは完璧に記録される。
2. バージョン2から5へ:進化の系譜
VPCフローログには「バージョン」が存在する。デフォルトのまま(Version 2)使っているプロジェクトも多いが、現代の複雑化したクラウドアーキテクチャ(Transit Gatewayや複数のVPCを跨ぐ構成)では、Version 2の情報だけでは目隠しでデバッグしているようなものだ。
Version 2:すべての基本
初期のフォーマットで、以下の項目が含まれる。
srcaddr/dstaddr: 送信元・送信先IPsrcport/dstport: ポート番号protocol: IANA番号(6はTCP、17はUDP)action:ACCEPT(許可)またはREJECT(Security GroupやNACLによる拒否)log-status: ログ自体の状態
Version 3 〜 5:痒いところに手が届く拡張
ここが今回の本題だ。V3以降で追加されたフィールドこそが、現代のSREにとっての「武器」になる。
tcp-flags(V3): これが真骨頂だ。SYN, ACK, FIN, RSTといったフラグをビット論理和で示す。3ウェイ・ハンドシェイクがどこで失敗したか一発でわかる。instance-id/interface-id(V3): どのEC2インスタンスが通信の主体か、IPの付け替えが発生していても追跡できる。pkt-srcaddr/pkt-dstaddr(V4): NATゲートウェイやロードバランサーを経由する際、「本当のオリジンIP」と「中継されたIP」を区別するために不可欠だ。flow-direction(V4):ingress(内向き)かegress(外向き)か。traffic-path(V5): 通信がどこを通ったか(IGW経由か、VPC Peering経由か、それともLocalか)を数値で示す。
—
3. 実践:V5フォーマットを定義する
最新の知見を詰め込んだフローログを作成する場合、マネジメントコンソールで「デフォルト形式」を選んではいけない。「カスタム形式」を選択し、以下のようなフィールド構成で定義するのが、現場のプロの流儀だ。
AWS CLIによるログ作成例
以下のコマンドは、特定のVPCに対して、S3へV5相当のフル情報を出力する設定だ。
aws ec2 create-flow-logs \
--resource-type VPC \
--resource-ids vpc-0123456789abcdef0 \
--traffic-type ALL \
--log-destination-type s3 \
--log-destination arn:aws:s3:::my-flow-log-bucket/prefix/ \
--log-format '${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status} ${tcp-flags} ${type} ${pkt-srcaddr} ${pkt-dstaddr} ${region} ${az-id} ${sublocation-type} ${sublocation-id} ${flow-direction} ${traffic-path}'
この --log-format の指定順序が、そのままログファイルの列挙順になる。
—
4. 現場でのトラブルシューティング:tcp-flagsを読み解く
デバッグにおいて、tcp-flags は雄弁だ。この値は整数値で記録されるため、16進数やバイナリに変換して解釈する。
2(SYNのみ): クライアントが接続を試みているが、サーバーから返事がない(タイムアウトの兆候)。4(RSTのみ): 接続が強制拒絶された。ポートが閉まっているか、Security Groupで弾かれた可能性がある。18(SYN+ACK): サーバー側は正しく応答している。
Pythonによる簡易解析スクリプト例
S3から降ってきたフローログ(Gzip形式)を解析して、REJECT された通信のうち、特に tcp-flags が立っているものを抽出するコード片を紹介しよう。
import gzip
import csv
def analyze_flow_logs(file_path):
# フローログを開く(通常は.gz形式)
with gzip.open(file_path, 'rt') as f:
# スペース区切りのデータを読み込み
reader = csv.reader(f, delimiter=' ')
for row in reader:
# ログフォーマットに合わせてインデックスを調整
# ここでは V5 カスタムフォーマットを想定
action = row[12]
src_ip = row[3]
dst_ip = row[4]
tcp_flags = int(row[14]) if row[14] != '-' else 0
# Security Groupで拒否されたSYNパケットを探す
if action == 'REJECT' and (tcp_flags & 2):
print(f"[ALERT] Connection Rejected: {src_ip} -> {dst_ip} (SYN detected)")
# 実行イメージ
# analyze_flow_logs('log_file.log.gz')
—
5. SREの知恵:なぜ pkt-srcaddr が重要なのか
最後に、中級者以上が必ず押さえておくべき pkt-srcaddr の話をしよう。
従来の srcaddr は、ENIの視点での送信元IPだ。しかし、ネットワークの境界(NAT Gatewayなど)では、IPパケットのヘッダーが書き換わる。
pkt-srcaddr には、カプセル化される前の、パケットヘッダーにある本来のIPが記録される。
もし君がマルチアカウント構成で Transit Gateway を使い、複雑なルーティングをしている場合、srcaddr だけを見ていると「すべて NAT Gateway の IP」に見えてしまうことがある。犯人(送信元)を特定するには、pkt-srcaddr を見るしかないのだ。
まとめ
VPCフローログは、単なるテキストの羅列ではない。それは、クラウドというブラックボックスの中で何が起きているかを証明する、唯一の「事実」だ。
1. Version 5 を活用せよ: tcp-flags や traffic-path がなければ、現代のトラブルシューティングは完結しない。
2. フォーマットを固定せよ: 解析スクリプトを組むなら、カスタムフォーマットで列の順序を厳密に定義すること。
3. 拒否(REJECT)だけでなく許可(ACCEPT)も追え: 正常な通信パターンを知らなければ、異常に気づくことはできない。
次にネットワークで原因不明の遅延や切断が起きたとき、慌ててコードを修正する前に、フローログという名の「足跡」を辿ってみてほしい。そこには必ず、パケットが残した真実が刻まれている。
コメント