【実務・中級編】 VPCフローログ(VPC Flow Logs)を用いたパケットメタデータのキャプチャ – クラウドインフラと仮想化ネットワーク実践ガイド

はじめに:夜間障害の現場で、私たちは何を見ているのか

「おい、また本番環境の特定マイクロサービスから、外部の決済APIへのリクエストがタイムアウトしているぞ。セキュリティグループもルートテーブルも完璧なはずなのに、いったいどこでパケットがドロップしているんだ……!」

真夜中のアラート対応。冷や汗をかきながらAWSコンソールを叩くシニアエンジニアの背中を、あなたも見たことがあるかもしれません。クラウドネイティブな世界では、私たちは物理的なケーブルやスイッチに触れることができません。仮想VPCの海を泳ぐパケットの生死を握るのは、ロジックとログだけです。

ここで最強の武器となるのが VPCフローログ(VPC Flow Logs) です。
「あぁ、あれね。S3に吐き出してAthenaで集計するやつでしょ?」と思ったそこのあなた。それだけでは、この機能が持つ本当のポテンシャルを半分も見落としています。VPCフローログは、単なる死活監視の監査証拠(Audit Trail)ではありません。パブリックサブネットとプライベートサブネットの境界、そしてInternet Gateway(IGW)という「関所」を通過するすべてのパケットの生態系を暴く、最高にエキサイティングなメタデータなのです。

今回は、ネットワークの基礎から、実務で使える生々しいログ解析のテクニックまで、現場の知見を総動員して徹底的に解説します。

—

1. VPCフローログのメカニズムとパケットの旅

まずは、VPCフローログがどのように生成されるのか、その裏側の挙動を解剖しましょう。

よくある誤解として、「VPCフローログを有効にすると、パケットのペイロード(中身のデータ)がすべてキャプチャされてS3に保存される」と思っている人がいますが、それは間違いです。もしそんなことをしたら、ストレージ代が爆発し、プライバシー規制(GDPRや個人情報保護法)に引っかかります。

VPCフローログが記録するのは、パケットの「メタデータ(通信の履歴書)」です。
正確には、AWSのハイパーバイザー層(ENI: Elastic Network Interfaceのレイヤー)で一定時間(デフォルトの集約間隔は1分、最短で10秒も可能)に観測されたトラフィックをサンプリングし、IPFIX(IP Flow Information Export)に近い形式でまとめて出力しています。

パブリック・プライベート・IGWを跨ぐ通信のライフサイクル

次のようなよくある3層アーキテクチャを想像してください。

[ 外部インターネット ]
        │
  (Internet Gateway / IGW) ─── ★ここでIGW境界の拒否/許可をキャプチャ
        │
[ パブリックサブネット (ALB) ]
        │
  (NAT Gateway or 内製プロキシ)
        │
[ プライベートサブネット (Web/API App) ]

1. インバウンド方向:外部クライアントからパブリックサブネットのALBに向かう通信が、Internet Gateway に到達します。もしここでNetwork ACLやセキュリティグループ、あるいはAWS WAF等で弾かれた場合、VPCフローログには REJECT という非情なステータスが刻まれます。
2. アウトバウンド方向:プライベートサブネットにあるバックエンドAPIが、外部のSaaSやWeb APIへリクエストを飛ばす際、パケットはNAT GatewayやIGWを経由して外に出ていきます。

ここで重要なのは、「どこでログを有効にするか」です。
ENI単位、サブネット単位、あるいはVPC単位でフローログを有効にできますが、トラブルシューティングの初動では、問題の切り分けのためにサブネット単位、あるいはIGWのアタッチされているVPC全体で有効にしておくのが鉄則です。

—

2. ログフォーマットの深掘りと「絶対に知るべき」フィールド

AWSのデフォルト・フローログ・フォーマットは、次のようなCSV形式の文字列です。

2 123456789012 eni-0123456789abcdef0 10.0.1.100 192.0.2.50 54321 443 6 5 320 1672531200 1672531260 ACCEPT OK

一見すると暗号のようですが、シニアSREの眼には、これが一つの美しいドラマのように映ります。実務で特に注目すべき主要なフィールドをピックアップして解説します。

| フィールド名 | サンプル値 | 現場での解釈と重要性 |
| :— | :— | :— |
| version | 2 | フローログのバージョン。拡張フォーマット(version 3〜5)では、パケットの方向(pkt-src-addr等)も取れます。 |
| account-id | 123456789012 | マルチアカウント環境でS3バケットに集約する際、どのAWSアカウントからの通信か一発で特定できます。 |
| interface-id| eni-... | どのENIを通過したか。EC2、RDS、ALB、ENI型NAT Gatewayのどれに紐づくかが分かります。 |
| srcaddr / dstaddr | 10.0.1.100 / 192.0.2.50 | 送信元と宛先のIPアドレス。プライベートIPとパブリックIPの変換(NAT)前後を追うのに不可欠です。 |
| srcport / dstport| 54321 / 443 | ポート番号。Web API開発であれば、443 (HTTPS) や 80 (HTTP) 以外に変なポートが空いていないか監視します。 |
| protocol | 6 | IANAプロトコル番号。6 は TCP、17 は UDP、1 は ICMP です。 |
| packets / bytes | 5 / 320 | 送受信されたパケット数とバイト数。DDoSやデータ漏洩の兆候を検知する重要なメトリクスになります。 |
| start / end | Unix Epoch | フローの開始・終了時刻。集約間隔(1分など)の間に発生した通信のタイムスタンプです。 |
| action | ACCEPT / REJECT | 最重要。 セキュリティグループやNetwork ACLによって許可されたか、拒否されたかを示します。 |
| log-status | OK / NODATA / SKIPDATA | ログ自体の健全性。NODATA が続く場合、そのENIに全くトラフィックがないか、ログの吐き出しに失敗しています。 |

バージョン5(v5)で追加されたモダンなフィールド

もし可能であれば、フォーマットはカスタム(あるいは最新バージョン)に設定し、以下のフィールドを追加することをお勧めします。

  • traffic-path:パケットがどのようにルーティングされたか(例:IGWを経由したか、VPC Peering経由か)
  • pkt-src-addr / pkt-dst-addr:NAT等で書き換えられる前の、真のパケット送信元・宛先IP

これがあると、複雑なルーティング環境でのパケット迷子を一撃で解決できます。

—

3. 実践:VPCフローログの有効化とパケット検証

それでは、実際に手を動かして環境を整え、ログを収集できるようにしましょう。
今回はTerraformを用いて、特定VPCのフローログをCloudWatch Logs、およびS3バケットへ出力するインフラストラクチャのコード例を示します。

TerraformによるVPCフローログの設定例

# フローログの出力先となるS3バケットの定義
resource "aws_s3_bucket" "flow_log_bucket" {
  bucket        = "my-company-prod-vpc-flow-logs-bucket"
  force_destroy = true

  tags = {
    Environment = "production"
    ManagedBy   = "Terraform"
  }
}

# S3バケットの暗号化設定(セキュリティ要件の基本)
resource "aws_s3_bucket_server_side_encryption_configuration" "flow_log_encryption" {
  bucket = aws_s3_bucket.flow_log_bucket.id

  rule {
    apply_server_side_encryption_by_default {
      sse_algorithm = "AES256"
    }
  }
}

# フローログ用のIAMロール
resource "aws_iam_role" "flow_log_role" {
  name = "vpc-flow-log-to-s3-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "vpc-flow-logs.amazonaws.com"
        }
      }
    ]
  })
}

# IAMポリシーの定義(S3への書き込み権限)
resource "aws_iam_role_policy" "flow_log_policy" {
  name = "vpc-flow-log-to-s3-policy"
  role = aws_iam_role.flow_log_role.id

  policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = [
          "s3:CreateBucket",
          "s3:PutObject",
          "s3:GetBucketLocation"
        ]
        Effect   = "Allow"
        Resource = [
          "${aws_s3_bucket.flow_log_bucket.arn}",
          "${aws_s3_bucket.flow_log_bucket.arn}/*"
        ]
      }
    ]
  })
}

# VPCフローログ自体のリソース定義
resource "aws_flow_log" "main_vpc_flow_log" {
  iam_role_arn    = aws_iam_role.flow_log_role.arn
  log_destination = aws_s3_bucket.flow_log_bucket.arn
  traffic_type    = "ALL" # ACCEPTだけでなくREJECTも含めてすべて記録
  vpc_id          = "vpc-0123456789abcdef0" # 対象のVPC ID
  log_format      = "$version $account-id $interface-id $srcaddr $dstaddr $srcport $dstport $protocol $packets $bytes $start $end $action $log-status $subnet-id"

  tags = {
    Name = "prod-vpc-flow-log"
  }
}

—

4. Web API開発者のためのトラブルシューティング手法

インフラエンジニアだけでなく、Web APIを設計・開発するエンジニアにとっても、VPCフローログを読めることは強力な武器になります。よくあるトラブルシナリオをどう解決するか、実務の現場における手順を見ていきましょう。

シナリオ:「外部の決済APIへリクエストが届かない(タイムアウトする)」

自社のプライベートサブネットにあるECS/Lambdaから、外部のサードパーティAPI(例: https://api.example-payment.com/v1/charge)へHTTPSリクエストを送ったところ、レスポンスが返ってこずにタイムアウトエラーになるケースです。

1. CloudWatch Logs Insights / Athenaでのクエリ発行

Amazon AthenaやCloudWatch Logs Insightsを使って、該当するプライベートIPや宛先ポート(443)のログを検索します。

CloudWatch Logs Insightsであれば、以下のようなクエリが即座に役立ちます。

fields @timestamp, srcaddr, dstaddr, srcport, dstport, protocol, action, packets, bytes
| filter dstport = 443 and action = "REJECT"
| sort @timestamp desc
| limit 20

2. 原因の切り分け

  • パターンA:action が REJECT になっている場合
  • 原因:セキュリティグループの egress(アウトバウンド)ルールが絞られすぎていて、外部への 443 ポートの通信がブロックされています。あるいは、Network ACLでプライベートサブネットからのアウトバウンドが制限されています。
  • パターンB:ログ自体が一切出力されない、あるいは ACCEPT になっているのに返ってこない場合
  • 原因(ログなし):そもそもアプリケーションが外に向かってパケットを飛ばせていません。ルートテーブルに 0.0.0.0/0 の宛先としてNAT Gateway(またはインターネットGW)へのルートが存在するか確認してください。
  • 原因(ACCEPTなのに不通):NAT Gatewayの向こう側、つまり相手方のファイアウォールやAWSの外部でパケットがドロップしています。あるいは、セキュリティグループのステートフルな特性を勘違いし、インバウンドの戻りパケットの経路でルーティングループが発生している可能性があります。

Pythonによる簡易的な疎通・ログ突合スクリプトの活用

開発現場では、ローカルから特定のAPIエンドポイントのIPを特定し、フローログ上の挙動と突き合わせるために、次のような簡易的なPythonスクリプトをサクッと書いて検証することもあります。

import socket
import sys

def resolve_target_api(hostname):
    """
    外部APIのホスト名からIPアドレスを解決し、
    インフラチームへVPCフローログ調査を依頼するための情報を出力する
    """
    try:
        ip_address = socket.gethostbyname(hostname)
        print(f"[+] ホスト名: {hostname}")
        print(f"[+] 解決されたIPアドレス: {ip_address}")
        print("    -> このIP宛ての dstaddr および dstport=443 のログをVPCフローログから検索してください。")
    except socket.gaierror as e:
        print(f"[-] 名前解決に失敗しました: {e}", file=sys.stderr)

if __name__ == "__main__":
    target = "api.example-payment.com"
    resolve_target_api(target)

現場のエンジニアが「なんとなく設定を変えてみる(お祈りデプロイ)」ではなく、このように「パケットがどこを通り、どこで拒否されたか(REJECT)」というファクトベースで会話できるようになると、障害解決のスピードは圧倒的に跳ね上がります。

—

5. おわりに:ログを制する者はクラウドネットワークを制す

今回は、VPCフローログの基礎から、パブリック・プライベート・IGWを跨ぐ通信のトラッキング、Terraformによる実装、そして実務でのトラブルシューティング手法までを一気に解説しました。

クラウドのインフラはブラックボックスに見えがちですが、VPCフローログという「確かな足跡」を正しく読み解くスキルがあれば、見えないパケットの流れが手に取るように見えてきます。深夜の障害対応で「よし、ここがREJECTされている原因はこれだ!」とピンポイントで突き止められた瞬間の快感は、シニアSREならではの醍醐味です。

ぜひ、あなたのプロジェクトでもVPCフローログの収集と、いざという時のクエリ環境(AthenaやInsights)を整えておいてください。あなたのシステムの信頼性は、今日から確実に一段階引き上げられるはずです。

コメント

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