NFSv4クライアントの作り方

検証環境

NFSセキュリティメモ

NFSについてググって見ると使用状況に応じて色々と苦労している点が見られる。 Kerberos 必須という人も居れば不要という人も居るわけで、ここでは以下のアンセキュアな環境を前提とする。

専用NIC(VLAN)割り当て

NFS共有用に専用NIC(VLAN)を割り当てる。そのNICにはNFS以外のサービスは提供しない。

  • GbEはいいぞ。単体~数台なら十分以上の性能を発揮する。
  • これは「同時」数台が帯域を使い込むような状態を想定しているので、数台がネットワークに存在するだけで飽和することを意味しない:-)。
  • 可能なら10GbEだろうけど高いし。
  • 検証環境では同一ホスト内にNFSサーバーとNFSクライアントを共存させてみたが、単純に / 以下を対象に tar(1) で固めただけで、1.6Gbps の性能が出た。
  • つまり単体で最大性能発揮しようと思ったらGbEは足りないかもしれないけど、10GbE埋めるのは結構大変。
  • ましてや「複数台が同時に」という確率と合わせると数台程度ならGbEでも余裕。
  • まぁアレだ。キャパシティプランニングで、動画再生のような常時帯域を使いまくるような前提は勘弁な。

パケットフィルタリング無しで

ipfw/pf/iptables/tcpwrapper といったパケットフィルタリングを行わない。

  • NFSv4に絞ってるので制限しやすくなってるが、専用ネットワークならそれほどの必要性を感じない。
  • 不特定多数の人が使うような用途で、NFSクライアントの偽装やら root 権限奪取やら、あるいはそれに準じるようなアクセスがあることを想定しているなら、Kerberos 認証とか IEEE 802.1X(認証VLAN)とか IEEE 802.1AE(MACsec)とか導入した方がいいと思うの(言ってることの現実性はテキトー)。

認証や暗号化・アクセス制御は無しで

認証?何それ。UNIXアカウント一択(デフォルトの -sec=sys)で。

  • NFSクライアントとNFSサーバーでのファイル所有者の取り扱いは可能な限りシームレスで、つまり、root は root として扱う(違うと色々面倒なんだよ)。
  • Kerberos は Kerberos で大変なんだよ。 orz
  • 通信の暗号化?ちょっ(ry。
    • Kerberos 有効にしないとアカンって。
    • IPsec?パケットは暗号化されるけど、NFSクライアントで tcpdump(8) したらバレるよねぇ。
    • あぁ。VPN越しなら IPsec もアリか。
  • SELinux の類い。
    • 自分アレ、コントロール(ステップアップ)できないので、disabled の扱いで。

結論

とりあえず少しずつステップアップすることがぢゅーよー、ということで、この手順を参考に難しいことに挑戦してみてください。

インストール

インストール

yum -y install nfs-utils

NFSクライアント・サーバーともに、nfs-utils のインストールで全てまかなえてることになっている。

ディレクトリ作成

mkdir -p 0755 /export

自動起動設定

chkconfig rpcbind on
chkconfig netfs on
chkconfig rpcidmapd on

chkconfig rpcgssd off
chkconfig rpcsvcgssd off
chkconfig nfs off
chkconfig nfslock off

セットアップ

MTU値の設定

今時のファイル共有ならGbEや10GbE当たり前なので、MTU値を設定する。 MTU値はネットワーク依存で、通信に絡んでいる一番小さな値を指定することになる。 必ずしも9000(バイト)とは限らないので、ちゃんと調べよう(&設定しよう)。

なお手動で設定できるが、設定した瞬間にMTU値が反映される(インターフェース的な問題よりもTCP的に)かわからなかった。 即座に反映されたようにも見えるし、umount→mount したら使ってたような気がしないでもなし。 たぶん、リンクダウン・アップした方がいいとは思うけど。

ip link set ethn mtu 9000
ip link set ethn down
ip link set ethn up

リンクダウン時に、そのインターフェースが持っていた経路情報を失うので(設定してなければ問題無い)、厳密には service network restart の方がいいかもしれない。

あるいはそもそも論として、再起動(shutdown -r now)してしまうのが吉。再起動後、インターフェースの設定を確認する。

# ip link show ethn
m: ethn: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 9000 qdisc mq state UP qlen 1000
    link/ether 00:0c:29:XX:XX:XX brd ff:ff:ff:ff:ff:ff

また、CentOS(RHEL)では、IPアドレス設定が、静的設定か動的設定かで、設定ファイルが分かれる。

/etc/sysconfig/network-scripts/ifcfg-ethn(静的設定環境用)

DEVICE=ethn
TYPE=Ethernet
BOOTPROTO=static
HWADDR=00:0c:29:xx:xx:xx
IPADDR=XXX.XXX.XXX.XXX
PREFIX=XX
NM_CONTROLLED=no
MTU=9000
ONBOOT=yes

/etc/dhclient-ethn.conf(動的設定環境用)

default interface-mtu 9000;
supersede interface-mtu 9000;

ググるとごちゃごちゃ設定(しかもグローバルに)してるケースがあるが、本質的には上記2行だけでok。 環境によってはどちらか1行でもok。 もしかしたら良きに計らってくれてるかもしれないくらい(DHCPサーバーがMTU値を広告してくれる)。

たまたま /etc/sysconfig/network-scripts/network-functions のコード読んでたから知ってたけど、意外と知られてないのかな。

/etc/sysconfig/nfs

   1 --- /etc/sysconfig/nfs.orig     2016-05-11 15:22:22.000000000 +0900
   2 +++ /etc/sysconfig/nfs  2016-06-06 19:32:42.649929205 +0900
   3 @@ -69,7 +69,7 @@
   4  #
   5  #
   6  # Optional arguments passed to rpc.idmapd. See rpc.idmapd(8)
   7 -#RPCIDMAPDARGS=""
   8 +RPCIDMAPDARGS="-C"
   9  #
  10  # Set to turn on Secure NFS mounts.
  11  #SECURE_NFS="yes"

/etc/idmapd.conf

   1 --- /etc/idmapd.conf.orig       2015-07-24 17:27:51.000000000 +0900
   2 +++ /etc/idmapd.conf    2016-06-06 14:34:41.302648213 +0900
   3 @@ -3,6 +3,7 @@
   4  # The following should be set to the local NFSv4 domain name
   5  # The default is the host's DNS domain name.
   6  #Domain = local.domain.edu
   7 +Domain = アカウント識別用ドメイン
   8 
   9  # The following is a comma-separated list of Kerberos realm
  10  # names that should be considered to be equivalent to the

/etc/fstab

NFSクライアントサーバーIP:/NFSv4ライアント名  /export  nfs4  defaults,soft,intr,noexec,nosuid  0  0

上記設定を/ etc/fstab に追加する。

オプション名

意味

備考

soft

intr

noexec

nosuid

手動でマウントするなら、以下の通りとなる(必要なデーモンが全て立ち上がってる前提で)。

mount -t nfs4 -o defaults,soft,intr,noexec,nosuid NFSクライアントサーバーIP:/NFSv4ライアント名 /export

アカウント作成

postgres

groupadd -g 5432             postgres
useradd  -u 5432 -g postgres postgres

CentOS では postgres アカウントのUID:GIDは本来 26:26 である。後述する rpc.idmapd のバグのため、NFSサーバーのUID:GIDと一致させる。

またこの作業は PostgreSQL サーバーをインストールする前に実施するが、すでにインストールされた状態であれば、UID:GIDを変更の上、ディレクトリやファイルの所有者を探し出して変更すること。

groupmod -g 5432             postgres
usermod  -u 5432 -g postgres postgres

find / -uid 26 -print0 | xargs -0 chown -h postgres
find / -gid 26 -print0 | xargs -0 chgrp -h postgres

CentOS 6.x での相互運用問題

CentOS 6.8(おそらく CentOS 5.11 も) との相互運用では以下の点に注意する必要がある。

  • NFSサーバー・クライアント間でUID/GIDを合致させないといけないバグがある(NFSv4の仕様上、バグ認定)。
  • というのもNFSクライアント(CentOS 6.8)で postgres(26):postgres(26) のプロセスがアクセス(cd など)した時の、NFSサーバーへのユーザー問い合わせ結果を tcpdump(8)した結果、「postgres」ではなく「26」という文字列をNFSサーバーに問い合わせ(fattr_owner)ている現象を確認した。
  • なお、chown(8) や ls(1) した時には問題無い。
  • 本現象について調査したところ、下記のバグがレポートされていることを確認した。
  • バグレポートでは以下の点から、CentOS 6 系(少なくとも 6.8、2016年06月09日現在)以下には反映されていないものと考える。
    • バグレポートで言及されているディストリビューションが FedoraCore 17 である。

    • CentOS 6(RHEL6) は FedoraCore 12/13 ベースである。

    • 更に CentOS 6 の nfs-utils のバージョンは 1.2.3 であるが、FedoraCore 17 では 1.2.6 である。

    • FedoraCore 17 ベースの CentOS 7 では問題無いと思われる(未検証)。

よくある質問とその答え

Q.ジャンボパケットで通信してますかー?

A.大丈夫だ。問題無い。(なぜ?)

サーバーやクライアントはもちろんのこと、サーバーとクライアントの間を結んでいるネットワーク機器の全てでジャンボパケットに対応している必要がある。 単純にジャンボパケットが通るか(設定が正しいのか)確認するのに ping を使う。

# ping -M do -s 8972 NFSv4サーバーのIP
PING NFSv4サーバーのIP (NFSv4サーバーのIP) 8972(9000) bytes of data.
8980 bytes from NFSv4サーバーのIP: icmp_seq=1 ttl=64 time=0.160 ms
8980 bytes from NFSv4サーバーのIP: icmp_seq=2 ttl=64 time=0.151 ms
^C
--- NFSv4サーバーのIP ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1388ms
rtt min/avg/max/mdev = 0.151/0.155/0.160/0.013 ms

1バイトでもオーバーすると下記のようなメッセージが出力される。

# ping -M do -s 8973 NFSv4サーバーのIP
PING NFSv4サーバーのIP (NFSv4サーバーのIP) 8973(9001) bytes of data.
ping: local error: Message too long, mtu=9000
ping: local error: Message too long, mtu=9000
^C
--- NFSv4サーバーのIP ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1349ms

しかし、クライアントサイドは問題無くても、途中経路またはサーバーサイドにMTUミスマッチ(典型的には 1500 のまま)があると無応答となる。 この場合、サーバーサイドに問題が無いとすると、特定は非常に困難になる。 一台一台、地味に特定していく必要がある。

ping での通信に問題が無ければ、最低限、ネットワーク周りの設定に問題は無い。

しかし実際にNFS通信(over TCP)がその状態で通信できているか確認するのは難しい。 特に手動で設定した直後は、設定前のMTU値で通信していることがある。 この場合、tcpdump(8)を使えば観測できなくもないが、その場合、length 8948 というパケットが観測できれば、問題無い。

# tcpdump -npiethn host NFSv4サーバーのIP
  :
XX:XX:XX.XXXXXX IP XXX.XXX.XXX.XXX.782 > YYY.YYY.YYY.YYY.nfs: Flags [.], seq 54720:63668, ack 3705, win 1588, options [nop,nop,TS val 444521882 ecr 816267359], length 8948
  :

下記のように length 1448 のままだとMTU値変更が反映されていないか、サーバー側もMTU値が反映されていない可能性がある。

# tcpdump -npiethn host NFSv4サーバーのIP
  :
XX:XX:XX.XXXXXX IP XXX.XXX.XXX.XXX.782 > XXX.XXX.XXX.XXX.nfs: Flags [.], seq 333288:334736, ack 621, win 1040, options [nop,nop,TS val 2971896848 ecr 2075608049], length 1448
  :

そのあたり反映させるための操作が面倒なら、サーバーもクライアントも shutdown -r now してしまうのが吉。

参考文献

NFSv4/クライアント (最終更新日時 2016-07-24 23:27:06 更新者 NorikatsuShigemura)