FJCT Tech blog

富士通クラウドテクノロジーズ公式エンジニアブログです

富士通クラウドテクノロジーズ

FJCT/Tech blog

ニフクラとNSX・DFW のトラブルシューティング

この記事は 富士通クラウドテクノロジーズ Advent Calendar 2020 の18日目の記事です。

f:id:higc_fjct:20201218204347p:plain

はじめに

こんにちは。富士通クラウドテクノロジーズ株式会社の樋口です。 普段は NSX を中心にニフクラのインフラ運用管理をしています。 先日 12/15 に NSX-v 6.4.9 がリリースされました。 NSXNSX-v が開発終了を予定して NSX-T に移っていく予定ですが、 まだまだ NSX-v も現役で運用されています。

今日はニフクラで NSX をどういう風に運用しているかと、 NSX-v の DFW のトラブルシューティングについて記事にしたいと思います。

(内容は以前 VM Meetup Tokyo #1 でお話しした内容をアップデートしたものになります)

ニフクラと NSX

歴史

ニフクラは2010年から開始した国産のクラウドサービスです。 NSX はリリース直後から検討をしていて、2015年に導入しました。 2017年には VMware Pertner Inovation Award 2016 をいただいています。

f:id:higc_fjct:20201218205843p:plain
ニフクラとNSXの歴史

利用規模はグローバルで見ても最大規模と聞いています。

現在、ニフクラで NSX は IaaS やデスクトップサービスなどで利用しています。

f:id:higc_fjct:20201218210334p:plain
利用している機能

f:id:higc_fjct:20201221120442p:plain
リモートアクセス VPN ゲートウェイのクライアントはニフクラ専用のスキンが設定されています。

NSX 運用体制

規模が大きいということもあり、NSX の運用は NSX 担当チームだけではなく、 顧客サポート担当、ニフクラアプリケーション担当、vSphere担当、物理機器担当と協力して実施しています。 NSX 担当は、 NSX を利用したサービスの企画・設計・運用・開発を実施しています。

f:id:higc_fjct:20201218210536p:plain
NSX運用体制

顧客サポート担当は、ユーザーからの問い合わせを各技術要素に閉じずニフクラ全体の視点で対応をしています。 NSX で提供しているサービスも関係している場合協力して問題解決をしています。

ニフクラアプリケーション担当は、ユーザーからのリクエストを受け付け NSX へ設定を入れる UI や内部処理の開発をしています。 ニフクラサービスの仕様や、ユーザーがニフクラで設定したことを NSX でどのような設定になるかということを協力して決めています。

vSphere 担当者は、 vCenter や ESXi などの管理をしています。 NSX の運用は vSphere の運用と切り離せません。 vCenter のバージョンアップ、 ESXi 内 NSX vib のインストール・バージョンアップ、細かいところだとファイアウォール用のログ出力設定など、 定常的な運用について NSX を考慮して実施しています。

物理機器担当者は、主に物理機器で構成されたアンダーレイのネットワークを管理しています。 ニフクラのネットワーク設計を検討したり、 通信系のトラブルがあった場合、ネットワーク全体をみたトラブルシューティングをする時に連携しています。

NSX 運用ツール

規模が大きいということもあり NSX 1つ1つの正常性の確認や操作を手動で実施すると時間がかかってしまします。 そのため、アプリケーションを開発したり OSS を利用して運用のシステム化をしています。 以下が、ニフクラの NSX 周りで利用しているシステムを書いた一枚の図です。

f:id:higc_fjct:20201218210643p:plain
NSX運用システム全体像

構成管理は Ansible で行っています。 GitLab 上のコードをチーム内のマスター情報として管理しています。 NSX の構築や設定変更については Ansible を使って実行しています。 ニフクラ独特の設定など足りない Ansible module については開発して補っています。

監視については、 Zabbix で一元管理しています。

独自開発のアプリケーションで NSX API 実行結果を解析し Zabbix に情報を送っています。 独自開発のアプリケーションは Python で開発しています。 クライアントライブラリについては OpenAPI の定義ファイルを作成し Swagger Codegen を利用して生成しています。 (以前は nsxramlclient を利用していたのですが、NSX の中でも限られた機能のみを利用しているのでそちらの方が管理しやすいため変更しました。)

NSX Manager のログも監視に利用しています。 fluentd でログを解析し、異常なログを発見した場合に気が付けるようにしています。

なるべく監視では、ログではなく API 実行結果を利用するようにしています。 ログからは異常の発生はわかるのですが、そのログに対応した問題の復旧をソフトウェアで判断することが難しいためです。

NSX のログをためて検索できるようにしています。 ログの検索基盤は Elastic Stack を使って構成されています。 ユーザーがコントロールパネルで確認することや、NSX運用者が確認することができます。 NSX Manager や NSX Edge からのログは fluentd でパースしています。 ESXi からのファイアウォールのログ(dfwpktlogs.log)のパースは Go 言語で内製開発したサービスを利用しています。

運用基盤では上記の通り、自分たちで開発できる箇所を多く残すようにしています。 特殊なトラブルや要件があったときに柔軟な対応ができるようにするためです。 vRNI や VROps についても魅力的な機能だと思っていますが利用していません。

最近の取り組みとしては、ニフクラアプリから直接 NSX を操作せず、 NSX 管理者が中間 API サーバーを用意するという取り組みをしています。

f:id:higc_fjct:20201218211123p:plain
中間API

ユーザー管理、NSX 以外のサービスとの連携はニフクラアプリ、 NSX の操作は中間 API サーバーが責任を持つようになります。 これにより、 NSX 管理者は API コール順序の変更やログ出力など、運用上の要件をアプリケーションに反映させやすいなどのメリットがあります。 ニフクラアプリ担当者は NSX の仕様変更があったとしてもニフクラアプリの実装を変更する必要がなくなるなどのメリットがあります。 (これらの取り組みのために昨日のブログ NSX-T の Go 言語 SDK について調査しました(2020/12版) に書いていた検討をしていたりします。)

インフラ CI

運用システムを自社で準備をしています。 一度作成した運用システムは動作し続ける必要があります。 しかし、エンハンス時のバグ混入や連携しているサーバーのアップグレードなど、環境が変化することによって不具合が発生する可能性があります。 サービスの品質を上げるためには、これらがプロダクション環境で利用される前に気がつけるようにしたいです。 そのために、テストをする必要があります。

f:id:higc_fjct:20201218211223p:plain
インフラCI

Ansible で構成に変更があった場合 CI で構築ができるかなどをテストするようにしています。 そのためには、テスト環境として、クリーンな vSphere の環境をオンデマンドで利用できる必要があり専用のツールを容易しています。 こちらに関して詳しくは、 @ntoofu さんの 続・IaaS基盤をテストする環境を作る話 - FJCT Tech blogをご覧ください。

DFW のトラブルシューティング

DFW とはなにか?

ここからは NSX の DFW に関する話になります。 DFW とは NSX の分散ファイアウォールのことです。

ファイアウォールは意図した通信以外を遮断するためのセキュリティ機能ですが、 設定ミスなど問題が発生すると意図せず通信を遮断してしまう可能性があります。 意図せず通信を遮断してしまうと、通信ができずシステム全体のトラブルになり、 サービスへの影響に発展します。 このためファイアウォールトラブルシューティングは重要です。

ここでは、 NSX の DFW のトラブルシューティング方法について説明いたします。

トラブルの種類は大きく分けると2種類

f:id:higc_fjct:20201218211803p:plain

NSX の DFW で発生するトラブルは大きく分けて以下の2種類になります。

  • (A) 設定が反映されていない
  • (B) ルールで許可しているがドロップされてしまう

A,B 2つのケースに分けて説明します。

設定が反映されていない場合の切り分け

トラブルシューティングの方法に入る前に NSX Manager へ操作をしてから実際に VM に反映するまでのプロセスを説明します。 変更までのプロセスは以下の通りです。

f:id:higc_fjct:20201218212028p:plain
ファイアウォールルール配信プロセス

  • (1) ユーザーが NSX Manager へルール更新操作をする
  • (2) NSX Manager が ESXi ごとにルールセットをまとめ配信する
  • (3) ESXi の vsfwd がルールを受け取る
  • (4) vsfwd から vsip 経由で dvfilterの設定が変更される

dvfilter は vNIC 毎に作成されるフィルタのことです。

「(1)ユーザーが NSX Manager へルール更新操作をする」 の確認

まず、意図したルールが NSX に入っているか確認します。 こちらは以下のように NSX の UI で確認することができます。

API で確認する場合は以下のようなリクエストを実行します。

% curl -s -k -u admin:$PASS -H 'Accept: application/json‘
  https://$NSXIP/api/4.0/firewall/globalroot-0/config
  | jq -r '.layer3Sections.layer3Sections[].rules[]

「(2) NSX Manager が ESXi ごとにルールセットをまとめ配信する」 の確認

NSX ではある時点のファイアウォールのルールは generation number という番号とともに管理されます。
番号はルール変更した時点の UNIX時間が利用されます。

APINSX Manager 上での最新のルールセットの generation number を確認するには以下を実行します。

% curl -s -k -u admin:$PASS -H 'Accept: application/json' “https://$NSXIP/api/4.0/firewall/globalroot-0/config” | jq -r .generationNumber
1557974013000

ESXi に配信されているルールセットが現在どの generation number かを確認するには以下の APIを実行します。

% curl -s -k -u admin:$PASS -H 'Accept: application/json' “https://$NSXIP/api/4.0/firewall/globalroot-0/status” | jq -r .
{
  "startTime": 1557974013000,
  "status": "published",
  "generationNumber": "1557974013000",
  "generationNumberObjects": "1558005383998",
  "clusterList": [
    {
      "clusterId": "domain-c113",
      "status": "published",
      "generationNumber": "1557974013000",
      "generationNumberObjects": "1558005383998",
      "hostStatusList": [
        {
          "hostId": "host-24459",
          "hostName": “xxxxx",
          "status": "published",
          "errorCode": 0,
          "startTime": 1557974017329,
          "endTime": 1558006428268,
          "generationNumber": "1557974013000",
          "clusterId": "domain-c113",

NSX Manager 上の最新のルールセットと、 ESXi に配信されているルールセットの generation number を確認することで、ルール配信が完了していることを確認できます。

過去のルール配信について確認したい場合はログを確認します。 vsm.log を見ると以下のようなログを確認することができ、ホストへルールが適用された時間を確認することができます。

クラスタへの配信開始

ConfigurationPublisher:89 - Updating Cluster domain-c136174 with Generation Number 1558017119337

ホストへの配信開始

ConfigurationPublisher:248 - Updating host host-160805 status for firewall, generation 1558017119337 ; StatusCode - 0, Status Message – 

ホストへの配信完了

FirewallDao:1241 - Host Status update for host host-160805 with latest generation number 1558017119337 , end time 1558017151737, errorCode null 

「(3) ESXi の vsfwd がルールを受け取る」

次に ESXi 内の状態を確認します。

まず、最新のルールセットが vsip まで展開されているかは ESXi で以下のコマンドを実行して確認します。

[root@host:~] vsipioctl loadruleset | grep ^Generation
Generation      : 1557974013000

過去、いつルールセットを受信したかは ESXi の vsfwd.log でも確認できます

2019-05-16T18:22:57Z vsfwd: [INFO] Applying firewall config to vnic list on host host-24459
2019-05-16T18:22:57Z vsfwd: [INFO] Applied RuleSet 1557974013000 on vnic 50190c49-ffcf-4e6c-fd97-3b12a0849333.001
2019-05-16T18:22:57Z vsfwd: [INFO] Applied RuleSet 1557974013000 on vnic 50190c49-ffcf-4e6c-fd97-3b12a0849333.000
2019-05-16T18:22:57Z vsfwd: [INFO] Applied RuleSet 1557974013000 for all vnics
2019-05-16T18:22:57Z vsfwd: [INFO] Sending vsa reply of domain-c113 host host-24459: 0

「(4) vsfwd から vsip 経由で dvfilter(vNIC 毎に作成されるフィルタ)の設定が変更される」 の確認

dvfilter で実際にどのような設定が展開されているかを確認します。

各 dvfilter は ID 単位で操作をすることができます。 まず操作をする dvfilter の ID を ESXi 上で以下のコマンドを実行し確認します。

[root@host:~] summarize-dvfilter
.
.
.
port 84136444 vm.eth0
  vNic slot 2
   name: nic-102377785-eth0-vmware-sfw.2
.
.
.

dvfilter の ID を取得したらその ID を利用して、 vsipioctl getrules を実行し設定されているルールを確認します。

[root@host:~] vsipioctl getrules -f nic-102377785-eth0-vmware-sfw.2
ruleset domain-c113 {
  # Filter rules
  rule 1006 at 1 in protocol tcp from addrset ip-ipset-7 to any port 22 accept;
  rule 1001 at 2 inout protocol any from any to any accept;
}

これにより、実際に VM の vNIC に適用されているファイアウォールルールを把握することができました。 上記の実行結果で from addrset ip-ipset-7 と記載されている箇所があります。 こちらは ip-ipset-7 というアドレスセットからの通信を指しています。 アドレスセットの内容を知るためには vsipioctl getaddrsets を実行します。

[root@host:~] vsipioctl getaddrsets -f nic-102377785-eth0-vmware-sfw.2
addrset ip-ipset-7 {
ip 10.20.0.32,
.
.
.

これにより、アドレスセットの実態を確認することができます。 アドレスセットは IPSet オブジェクトなど静的に設定したものもありますが、 ファイアウォールルールの Source や Destination に Security Group や VM など vCenter Object を指定したときには動的に設定が変化します。 vCenter Object を指定した場合 VMware tools が動作していないなどの理由により IP アドレスが展開されない場合があります。 対策としては、 VMware tools が正しく起動するようにするか、 NSX の設定で IP Detection Type で DHCP SnoopingARP Snooping をオンにするという方法があります。

まとめ

設定が反映されているかの切り分け方法と考えられる問題は以下の通りです。

  • 切り分け方法
    • 入れたルールが正しいか調べる
    • 配信されているか調べる
  • 考えられる問題
    • 入れたルールが正しくない
    • ESXi の vsfwd と NSX Manager が通信できない
    • VMware tools が停止している

ルールで許可しているがドロップするケースの切り分け

DFW ではルールテーブルにマッチしていても通信が遮断される場合があります。 TCP のフロー上異常だと判断されたケースです。 コネクショントラッキングテーブルで管理された TCP の状態と、パケットがマッチしない場合遮断します。 ここからは、こちらのメカニズムと遮断される例について言及します。

DFW のメカニズム

f:id:higc_fjct:20201218212211p:plain
DFWのメカニズム

DFW のフィルタには dvfilter ごとにコネクショントラッキングテーブルとルールテーブルを持っています。 パケットの内容が、コネクショントラッキングテーブルを参照し既存コネクションでTCPステートが一致した場合はフィルタを通過します。 新規コネクションであった場合は、ルールテーブルを参照し Allow のルールにマッチした場合はフィルタを通過します、 その時同時にコネクショントラッキングテーブルにエントリーを追加します。

ルールテーブルでドロップした場合の切り分け方法

ルールテーブルでドロップした場合の切り分け方法についてです。 ファイアウォールのログから確認することができます。 対象の vNIC をもつ VM が存在する ESXi 上の dfwpktlogs.log を参照してください。 以下のようなログで確認することができます。

       ルールにマッチしドロップ       ルールID   方向                   送信元->送信先        TCPフラグ
             |                   |    |                           |                |
INET match DROP domain-c171871/11064 IN 40 TCP 192.168.0.31/50325->192.168.0.32/80 S

ファイアウォール全体で拒否しているか切り分ける方法

ファイアウォール全体で拒否しているか確認する方法についてです。 dvfilter の統計情報から確認することができます。

[root@host:~] vsipioctl getfilterstat -f nic-16002942-eth1-vmware-sfw.2
PACKETS                       IN                OUT
-------                       --                ---
v4 pass:                         83                  3
v4 drop:                        608                  0

Drop と記載されている箇所からドロップされているパケット数を確認することができます。

上記の方法ではドロップされているパケットの有無や数がわかりますが、具体的にどのパケットが遮断されたのかわかりません。 少し手間がかかりますが、遮断されたパケットを把握する方法があります。 DFW 前後でパケットキャプチャを取得しその差分を確認する方法です。 ESXi 上で以下のコマンドを実行します。

ファイアウォール直前のパケットキャプチャ

pktcap-uw --capture PreDvFilter  --dvfilter $DVFILTER

ファイアウォール直後のパケットキャプチャ

pktcap-uw --capture PostDvFilter  --dvfilter $DVFILTER

コネクショントラッキングテーブルでドロップした場合の切り分け方法

コネクショントラッキングテーブルでドロップした場合の切り分け方法は少し手間がかかります。

一つの方法は以下の knowledge base より、コネクショントラッキングテーブルで拒否するような通信のケースを確認し、合致していないか調査することです。

具体的にどのパケットがコネクショントラッキングテーブルで拒否されているかを調べる場合、 「前述のファイアウォール前後のパケットキャプチャの差分」と、「dfwpktlogs.log」の差分を調べる必要があります。

続けて、具体的にどういった通信を行っている場合、コネクショントラッキングテーブルで拒否されるかの一例を紹介します。

コネクショントラッキングテーブルが理由でドロップするケース(1) 非対称ルーティング

コネクショントラッキングテーブルが理由で遮断するケースの一つとして非対称ルーティングがあります。

f:id:higc_fjct:20201218212318p:plain
通常のケースと非対象ルーティングのケースのウィンドウ

DFW はウィンドウの計算もしており、今まで通過したパケットからウィンドウサイズを把握していて、ウィンドウを超えた場合はドロップします。 非対称通信のような「行き/戻り」で「通信元/通信先」が一致しない場合、正しく計算することができません。 通信の内容が 65KB 以内であればできるが、このサイズを超えるとうまく通信できないようなケースはこちらの問題の可能性があります。

コネクショントラッキングテーブルが理由でドロップするケース(2) EST 状態で SYN を受け取った場合(6.2.3 で改善)

コネクショントラッキングテーブルが理由で遮断するもう一つのケースとして、 EST 状態で SYN を受け取った場合がありました。 こちらは NSX-v 6.2.3 で改善していますが紹介いたします。

f:id:higc_fjct:20201218212444p:plain
6.2.2までのハーフオープン時の挙動

クライアントが異常終了した場合などコネクションがリセットされるが、サーバーが ESTABLISHED 状態のまま(ハーフオープン状態)という、 サーバークライアント間で TCP ステートが一致しないことがあります。 この時クライアントはサーバーが ESTABLISHED 状態であるにもかかわらず、 SYN を送ってしまいます。 この場合 NSX-v 6.2.2 までは TCP ステートが一致しないため DFW で SYN パケットを遮断するという動作をしていました。

NSX-v 6.2.3 以降ではこの問題に対策がされています。

f:id:higc_fjct:20201218212554p:plain
6.2.3からのハーフオープン時の挙動

ハーフオープン時にクライアントから SYN パケットが送られた場合 DFW が 代理応答で ACK を返すようになりました(challenge ack)。 これにより、クライアントは SYNSENT 状態で ACK を受け取り、 RST を送信します。 この RST パケットで DFW を含めたクライアント、サーバー間の TCP ステートがクリアされ、再度コネクションを確立できるようになりました。

おわりに

今日はニフクラがどのように NSX を運用しているかと、 DFW のトラブルシューティング方法を紹介いたしました。 どなたかの参考になると幸いです。

明日の 富士通クラウドテクノロジーズ Advent Calendar 2020 は @tunakyonn による「ニフクラでTerraformのtfstateファイルを管理してみた」だそうです。 楽しみですね。