【テクニカル・上級編】 VPCフローログのレコードフォーマットとsrcaddr, dstaddr, packets, bytesフィールドの解析 – クラウド&コンテナネットワーク実践ガイド

VPCフローログの深淵:srcaddr・dstaddr・packets・bytesが語るパケットの真実と実戦的解析

ネットワークインターフェイスを通過するすべてのパケットの挙動を、クラウドの底流で静かに、そして確実に記録し続けるVPCフローログ。SREやクラウドアーキテクトであれば、トラブルシューティングやセキュリティ監査の文脈で一度はお世話になったことがあるはずだ。

しかし、出力されるCSVやJSONのレコードをただ眺めているだけで、その真の価値を引き出せていると言えるだろうか?

「なぜこの通信は突如としてレイテンシーが跳ね上がったのか」「どのPodが隠れファンクションとして帯域を枯渇させているのか」「巧妙に難読化されたスキャンパケットの兆候をどう捉えるか」。

今回は、VPCフローログの基本構造、特に srcaddr、dstaddr、packets、そして bytes の各フィールドが持つパケットレベルの物理的・論理的意味を解き明かし、Linuxカーネルやクラウドの仮想化レイヤー(ENI、SDNコントローラー)の挙動まで踏み込んだ実戦的解析手法を解説しよう。

—

1. VPCフローログの解剖学:レコードフォーマットの裏側

AWSやGCPなどのメガクラウドにおいて、VPCフローログは単なる「ログ出力機能」ではない。それはハイパーバイザーの仮想スイッチングレイヤー、あるいはSmartNIC(AWSのNitroカードなど)のハードウェアアクセラレーションによってインラインで集計される、極めて高精度なテレメトリーデータだ。

デフォルトのバージョン2フォーマットにおいて、ログの1行(レコード)は以下のようなスペース区切りの文字列として出力される。

2 123456789012 eni-0123456789abcdef0 192.168.1.50 10.0.1.100 54321 443 6 15 2250 1588800000 1588800060 ACCEPT OK

この各フィールドが何を意味するのか、パケットの往来というミクロな視点から再確認する。

コアフィールドの厳密な定義

  • srcaddr / dstaddr: パケットのIPヘッダーに含まれる送信元および宛先IPアドレス。ただし、これは「直前のホップ」ではなく、エンドツーエンドの通信におけるフローの向き(方向性)に依存する。
  • packets: 集計期間内(通常は最大60秒のウィンドウ)に観測されたパケットの総数。
  • bytes: 集計期間内に観測されたペイロードおよび各種ヘッダーを含むバイト数の総計。

ここで重要なのは、VPCフローログはパケット単位ではなく「フロー(5タプル単位)」で集約(Aggregated)されて出力される点だ。Linuxカーネルの netfilter(conntrack)や、BSDの pf が行うステートフルなセッション管理と同様に、同一の5タプル(ソースIP、デスティネーションIP、ソースポート、デスティネーションポート、プロトコル番号)を持つパケット群は、一定時間(通常60秒)のウィンドウ内で packets と bytes に累積加算される。

—

2. フィールドの深層解析:srcaddr, dstaddr, packets, bytes の相関関係

これら4つのフィールドを組み合わせることで、単なるトラフィック量だけでなく、アプリケーション層やトランスポート層の振る舞いを精密にプロファイリングできる。

A. パケットサイズ(平均パケット長)の算出によるプロトコル推定

bytes を packets で割ることで、そのフローにおける「平均パケット長」が算出できる。これが実務でどう役に立つか。

例えば、データベース(PostgreSQLやMySQLなど)へのクエリ通信や、KubernetesのgRPC(HTTP/2)通信では、小さなリクエストに対して比較的大きなレスポンスが返るため、平均パケット長は大きくなる傾向がある。
逆に、TCPのACKパケットばかりが大量に流れていたり、DDoS攻撃における小粒なUDPフラッド、あるいはKeep-Aliveの微小なプローブ通信が発生している場合、packets の値が極端に大きいにもかかわらず、bytes の増加量が不自然に少ない(平均パケット長が極小、例えば60〜80バイト前後)現象が観測される。

B. 非対称ルーティングとパケットロスの検知

VPC内のセキュリティグループやネットワークACL(NACL)、あるいはKubernetesのCilium / CalicoなどのCNI(Container Network Interface)におけるeBPFプログラムの挙動をデバッグする際、srcaddr と dstaddr の向きが鍵を握る。

例えば、パケットがクライアントからサーバーに向かって送信されているにもかかわらず、対応する逆向きのフロー(srcaddr と dstaddr が反転したもの)が全く記録されない場合、以下のいずれかの問題が発生していると断定できる。
1. セキュリティグループやNACLの egress / ingress ルールによる暗黙のドロップ(REJECT ではなく DROP の場合、フローログには REJECT ステータスがつかないか、あるいはフロー自体が記録されないケースがある)。
2. ルートテーブルのミス配置によるブラックホール。

—

3. 実戦的解析手法:AthenaとPythonを用いたボトルネック特定

大規模なマイクロサービス環境では、CloudWatch Logsに蓄積された数十GB〜TB規模のVPCフローログを目視で確認するのは不可能だ。AWS環境であれば Amazon Athena を用いてSQLベースでクエリを投げ、異常なトラフィックパターンをあぶり出すのがSREの常道となる。

以下に、帯域を極端に消費している(bytes が異常に大きい)上位の通信ペアを特定しつつ、パケット単価の歪み(DDoSや非効率なポーリング)を検知するための実践的なAthenaクエリを示す。

-- 過去24時間において、最もバイト数を消費しているフローのトップ10を抽出
-- さらに平均パケット長を計算し、プロトコルの特性をあぶり出す
SELECT
    srcaddr,
    dstaddr,
    dstport,
    protocol,
    SUM(packets) AS total_packets,
    SUM(bytes) AS total_bytes,
    -- 平均パケット長(バイト/パケット)を算出
    ROUND(CAST(SUM(bytes) AS DOUBLE) / NULLIF(SUM(packets), 0), 2) AS avg_packet_size,
    -- 1MBあたりのパケット密度を計算
    ROUND(CAST(SUM(packets) AS DOUBLE) / (SUM(bytes) / 1024.0 / 1024.0), 2) AS packets_per_mb
FROM
    vpc_flow_logs
WHERE
    -- パーティションプルーニングを効かせための時間指定
    day >= '2023-10-01'
    AND action = 'ACCEPT'
GROUP BY
    srcaddr,
    dstaddr,
    dstport,
    protocol
ORDER BY
    total_bytes DESC
LIMIT 10;

このクエリの結果、avg_packet_size が極端に小さく(例:64バイト〜128バイト)、かつ total_packets が数百万に達しているフローがあれば、それは正当なデータ転送ではなく、過剰なヘルスチェック、TCPの再送ループ、あるいは不正なスキャン活動である確率が非常に高い。

—

4. Linuxカーネルとネットワークスタックの最適化:フローログが示すサインへの処方箋

VPCフローログから得られた知見を、いかにインフラストラクチャのチューニングにフィードバックするか。ここでは、トランスポート層(TCP)とパケット処理のパフォーマンスを極限まで高めるための実務的アプローチに踏み込む。

TCPバッファチューニングとRWIN(Receive Window)の拡張

フローログ上で bytes の伸びが悪い割にレイテンシーが高い、あるいはスループットが頭打ちになっている場合、それはTCPのウィンドウサイズ(RWIN)が小さすぎることがボトルネックになっているケースが多い。

Linuxカーネルのネットワークパラメータをチューニングし、BDP(Bandwidth-Delay Product)に見合ったバッファを割り当てることで、メガクラウド間の巨大なデータ転送(クロスAZ間のレプリケーションなど)の効率を劇的に改善できる。

以下の設定を /etc/sysctl.d/99-custom-tcp.conf に記述し、適用する。

# TCPの送受信バッファの最小値、デフォルト値、最大値(バイト単位)
# 10GbE以上の高速ネットワーク環境を想定したアグレッシブな設定
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.ipv4.tcp_rmem = 4096 87380 16777216
net.ipv4.tcp_wmem = 4096 65536 16777216

# ウィンドウのスケーリングを有効化(大規模なBDPに対応)
net.ipv4.tcp_window_scaling = 1

# 輻輳制御アルゴリズムに BBR (Bottleneck Bandwidth and Round trip propagation time) を採用
# 従来のCUBICに比べ、ロス率の高いクラウド環境や長距離通信で圧倒的なスループットを発揮
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

設定を反映させるには、以下のコマンドを実行する。

sudo sysctl --system

このチューニングを行うと、VPCフローログ上の同一時間あたりの bytes 量が劇的に増加し、パケットあたりのスループット効率が向上することが確認できるはずだ。

—

5. セキュリティ監査と不正アクセスの自動検知(Pythonスクリプトによる実装)

最後に、セキュリティの観点からVPCフローログをどうハックするか。
悪意あるスキャナーや、侵害されたPodからの外部C2(Command and Control)サーバーへの通信は、通常のエンドポイントとは異なる奇妙な srcaddr と dstaddr の関係、あるいは短時間に多発するフローを生み出す。

S3に保存されたVPCフローログをリアルタイムあるいはバッチでフェッチし、異常な通信パターン(例えば、単一の srcaddr が短時間に多種多様な dstaddr の特定のポートに対して大量のパケットをばらまいている挙動、いわゆるポートスキャンや水平スキャン)を検知するPythonスクリプトの断片を提示する。

import boto3
import pandas as pd
from collections import defaultdict

def analyze_vpc_flow_logs(bucket_name, log_prefix):
    """
    S3上のVPCフローログを読み込み、ポートスキャンや異常なトラフィックを検知する
    """
    s3_client = boto3.client('s3')
    
    # 簡易的に最新のログオブジェクトを取得してデータフレーム化する処理を想定
    # (実運用ではAthenaやLambda + S3イベント駆動を使用することを推奨)
    print(f"Analyzing logs from s3://{bucket_name}/{log_prefix}...")
    
    # ダミーのデータフレーム(実際はS3のGZIPログ等をパースしてロード)
    # ログフォーマット: version, account-id, eni-id, srcaddr, dstaddr, srcport, dstport, protocol, packets, bytes, start, end, action, log-status
    data = {
        'srcaddr': ['192.168.1.50', '192.168.1.50', '192.168.1.50', '10.0.0.15'],
        'dstaddr': ['10.0.2.10', '10.0.2.11', '10.0.2.12', '192.168.1.1'],
        'dstport': [80, 443, 22, 53],
        'packets': [5, 2, 1000, 1],
        'bytes': [250, 100, 50000, 60]
    }
    df = pd.DataFrame(data)
    
    # 1つの送信元IPがアクセスしている異なる宛先IPの数をカウント(水平スキャン検知)
    scan_counts = df.groupby('srcaddr')['dstaddr'].nunique()
    
    suspicious_ips = scan_counts[scan_counts > 2].index.tolist()
    
    if suspicious_ips:
        print(f"[SECURITY ALERT] Potential port scan detected from source IPs: {suspicious_ips}")
        for ip in suspicious_ips:
            # 該当IPのフロー詳細を出力
            violators = df[df['srcaddr'] == ip]
            print(violators[['srcaddr', 'dstaddr', 'dstport', 'packets', 'bytes']])
    else:
        print("No anomalous scanning behavior detected.")

if __name__ == "__main__":
    # 実環境のバケット名とプレフィックスを指定して実行
    # analyze_vpc_flow_logs("my-vpc-flow-logs-bucket", "AWSLogs/123456789012/vpcflowlogs/")
    pass

このスクリプトのように、dstaddr の多様性(nunique())や、packets に対して bytes が不自然に小さいセッションの集積を監視アルゴリズムに組み込むことで、WAFやIDSが検知しきれないネットワーク層の異常をいち早くキャッチできる。

—

結びに代えて

VPCフローログは、クラウドネットワークの「脈拍」そのものだ。
srcaddr と dstaddr は通信の意思疎通の軌跡を描き、packets と bytes はその重みと熱量を物語る。

単なるログ保管庫の肥やしにしておくにはあまりにも惜しいこのデータを、Linuxカーネルの深い理解と適切な解析パイプラインによって解き放つこと。それこそが、現代のインフラエンジニアに求められる真のネットワークリテラシーであり、システムを極限のパフォーマンスと鉄壁のセキュリティへと導く唯一の道筋である。

コメント

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