現場のトラブル事例:断続的なネットワーク障害とローカルパケットキャプチャの限界
先週、私たちが運用している8台のESXiホストで構成されたVMwareクラスタで、非常に厄介なトラブルが発生しました。銀行の決済ゲートウェイと通信している決済用仮想マシン(VM)で、時折「SSL Handshake Timeout」エラーが発生するようになったのです。頻度は1時間あたり3〜5分程度、失敗率は全トランザクションの約4%でした。さらに厄介なことに、手動でcurlやpingを実行して疎通確認を行っても問題なく導通しており、HTTP 200が正常に返ってくる状態でした。
このような場合、多くのエンジニアはまずVMへSSH接続してtcpdumpを実行することを考えるでしょう。しかし、本番環境では大きな障壁が存在します。
- サードパーティ製アプライアンスVMとしてパッケージ化されており、root権限がなく、追加パッケージのインストールも一切許可されていない。
- PCI-DSSのセキュリティポリシーにより、情報漏洩やCPU負荷の上昇を防ぐため、カード情報を取り扱うサーバー上で直接パケットスニッファを動作させることが厳格に禁止されている。
- OS内部のiptablesやファイアウォールによる影響を受ける前の、仮想NIC(vNIC)レベルの生パケットを検証する必要がある。
VM自体には手を加えられない状況下で、唯一現実的なアプローチは、VMwareの仮想スイッチポートから直接トラフィックを抽出することでした。
問題の本質:仮想スイッチが他のVM宛てのパケットキャプチャを遮断する理由
vSwitchは標準的なレイヤー2スイッチとして動作します。仮想マシンAが仮想マシンBへパケットを送信すると、スイッチはMACアドレステーブルを参照し、宛先ポートへ直接フレームを転送します。そのため、同一ポートグループに存在する仮想マシンCには、それがブロードキャストやマルチキャストパケットでない限り、トラフィックは一切届きません。
この構造によってパケット衝突のリスクが排除され、テナント間のデータが安全に隔離されています。したがって、仮想マシンCでAとB間の通信を傍受するには、ハイパーバイザのスイッチング層で意図的に介入する必要があります。
VMwareインフラ上でパケットキャプチャを行う3つのアプローチ
アプローチ1:ポートグループでPromiscuous Mode(無差別モード)を有効化する
最も手軽な方法は、ポートグループのセキュリティポリシー設定でPromiscuous ModeをRejectからAcceptに変更することです。
メリット: 設定は1分未満で完了します。同じポートグループに接続されたWireshark実行用VMでパケットを受信できるようになります。
デメリット: セキュリティリスクが非常に高くなります。そのポートグループ内のすべてのVMが互いの通信を傍受できるようになってしまいます。さらに致命的な点として、キャプチャ対象VMとスニッファーVMが異なるESXiホスト上に存在する場合、この方法は機能しません。
アプローチ2:ESXi Shellでpktcap-uwコマンドを使用する
VMwareには、ESXiカーネル内にCLIツールpktcap-uwが標準で組み込まれています。VMが稼働しているホストへSSH接続し、スイッチポートIDを指定してパケットをキャプチャします。
# vSwitch上のポートID一覧を取得
esxcfg-vswitch -l
# ポート50331658のパケットをキャプチャしてデータストアに出力
pktcap-uw --switchport 50331658 --dir 2 -o /vmfs/volumes/datastore1/trace.pcap
メリット: スイッチ構成に依存せず、VMkernelレベルで極めて低レイヤーのパケットを捕捉できます。
デメリット: ESXiホスト上でSSHサービスを有効化する必要があり(セキュリティベースラインで通常は無効化されていることが多い)、データストアからローカル端末へpcapファイルをダウンロードする手間がかかります。緊急のトラブルシューティング時にリアルタイムでトラフィックを確認したい要件には適していません。
アプローチ3:vSphere Distributed Switch(vDS)でPort Mirroringを設定する
この機能は、物理CiscoスイッチにおけるSPAN/ERSPANの仕組みと同様です。vDSが対象VMのvNICからフレームを自動的に複製し、スニッファーVMのvNICへと転送します。クラスタ内で2台のVMが同一ホストにあるか別ホストにあるかにかかわらず、正常に機能します。
詳細な構築手順:vDSでのDistributed Port Mirroring設定
エンタープライズシステムにおいて、これは最も堅牢かつ安全なアプローチです。ESXiのSSHポートを開放する必要がなく、内部セキュリティポリシーに違反することもなく、リアルタイムでパケットをモニタリングできます。
ステップ1:専用のスニッファーVMを作成する
Ubuntu 22.04 LTSまたはWindows Serverを搭載したVMを構築し、Wiresharkとtsharkを事前にインストールしておきます。このVMには2枚の仮想NICを割り当てます。
- vNIC 1: 通常の管理ネットワークに接続し、SSHやRDPでの操作用として使用。
- vNIC 2: ミラートラフィック受信用として専用に割り当て(IPアドレスは絶対に設定しないでください)。
vSphere Client上でPG-Sniffer-Captureという名前の新しいDistributed Port Groupを作成し、vNIC 2に割り当てます。このポートグループのSecurityポリシーで以下の通り設定します。
- Promiscuous mode: Accept
- MAC address changes: Accept
- Forged transmits: Accept
ステップ2:監視対象VMのポートIDを確認する
vSphere Clientを開き、Networking > 使用中のvDSを選択 > 監視対象VMが属するDistributed Port Groupを選択 > Portsタブを開きます。対象のVM名を特定し、Port ID列の値を記録します(例:payment-gw VMのポート1024、スニッファーVMのvNIC 2のポート2048)。
ステップ3:Port Mirroringセッションの作成
- vDSの管理画面で、Configureタブ > Port Mirroringを開きます。
- Newをクリックしてセッション作成ウィザードを開始します。
- セッションタイプとしてDistributed Port Mirroringを選択します(送信元と宛先が異なるESXiホストにまたがっている構成に対応)。
- セッション名に
Mirror-Payment-GW-Traceと入力し、ステータスをEnabledに設定します。 - Sources項目:監視対象VMのポートID(
1024)を入力し、送受信両方向のパケットを確実にキャプチャするためトラフィック方向をIngress / Egressに設定します。 - Destinations項目:スニッファーVMの受信用vNICのポートID(
2048)を入力します。 - 設定内容を全体的に確認し、Finishをクリックします。
自動化によって複数ポートを一括設定する必要がある場合は、以下の標準PowerCLIスクリプトを実行できます。
# vCenter Serverへ接続
Connect-VIServer -Server vcenter.corp.local -User [email protected] -Password "SecretP@ss!"
# Distributed Switchの情報を取得
$vds = Get-VDSwitch -Name "vDS-Core-Cluster"
$vdsView = Get-View $vds
# ミラーセッションのパラメータを初期化
$configSpec = New-Object VMware.Vim.VMwareDVSConfigSpec
$session = New-Object VMware.Vim.VMwareDVSPortMirroringSessionConfigSpec
$session.key = "TraceSession01"
$session.name = "Live-Debug-Session"
$session.enabled = $true
$session.direction = "both"
$session.sourcePortKey = @("1024")
$session.destinationPortKey = @("2048")
$configSpec.portMirroringConfigSpec += $session
# API経由でvDSに設定を直接適用
$vdsView.ReconfigureDvs_Task($configSpec)
ステップ4:スニッファーVMでのパケットキャプチャと解析
スニッファーVMにログインします。パケット受信用vNICがLinux上でens224として認識されていると仮定し、パケットが正常に届いているかを簡易チェックします。
# 受信インターフェースに到達した最初の10パケットを確認
sudo tshark -i ens224 -c 10
# ポート443の全トラフィックをキャプチャしてpcapファイルに保存
sudo tcpdump -i ens224 -nn "tcp port 443" -w /tmp/payment_tls.pcap
payment_tls.pcapファイルをWiresharkで開くか、GUI上でens224インターフェースを直接監視します。検索バーに以下のディスプレイフィルタを貼り付けます。
tcp.port == 443 && (tcp.flags.reset == 1 || tls.record.content_type == 21)
このフィルタにより、TCP RST(異常切断)およびTLS Alert(証明書やTLSバージョンのネゴシエーション失敗)パケットを即座に特定できます。今回の実際のトラブル事例では、Wiresharkによって銀行側IPから送信されたTLS Alert (Level: Fatal, Description: Handshake Failure)パケットが捕捉されました。原因は、銀行側が事前の通知なしに暗号スイート(Cipher Suite)をアップグレードしたことで、決済ゲートウェイVM上の古いOpenSSLライブラリからの接続が拒否されていたことでした。
Port Mirroring運用における2つの鉄則
- トレース完了後は直ちにセッションを無効化する: トラフィックのミラーリングはvSwitchの帯域消費を倍増させます。2〜5 Gbps規模のトラフィックを扱うVMにおいてセッションを常時有効にしたまま放置すると、ESXiホストの物理アップリンク帯域を圧迫し、スニッファーVMのディスクI/Oボトルネックを引き起こす要因となります。
- トラフィック量が多い場合はSampling Rateを活用する: スループットの高いデータベースやキャッシュクラスタを監視する場合は、vDSセッション設定でSampling Rate(例:5パケットに1パケットのみ複製)を設定し、キャプチャ側マシンのネットワークインターフェースへの負荷を軽減してください。
