第18章 NFSサーバーの構築と運用

LPIC-2 209.2 相当

前章のSambaと並んで、Unix/Linux環境で長く使われている標準的なファイル共有方式がNFS(Network File System)です。

NFS — Unix系の標準的なファイル共有

サーバー側 /etc/exports
/srv/nfs/share  192.168.1.0/24(rw,sync,no_subtree_check)
$ sudo exportfs -a               # /etc/exportsの内容を反映(正常時は無出力)
$ sudo systemctl restart nfs-kernel-server   # Debian系のユニット名。正常時は無出力
$ showmount -e サーバーIP        # 公開されている共有一覧を確認(クライアント側)
Export list for 192.168.1.10:
/srv/nfs/share 192.168.1.0/24

この行のこの値に注目: showmount -eの出力にあるExport list for ...以降に、実際にサーバーが公開している共有パスと、それぞれにアクセスを許可されているクライアント範囲が1行ずつ並びます。ここに目的の共有が表示されなければ、/etc/exportsの記述漏れか、exportfs -aの反映漏れが原因です。

ディストリビューションによる違い: nfs-kernel-serverはDebian系のサービス(ユニット)名です。RHEL系ではnfs-serverという名前になるため、sudo systemctl restart nfs-serverのように読み替えてください。
クライアント側でマウント
$ sudo mount -t nfs サーバーIP:/srv/nfs/share /mnt/nfs   # 正常時は無出力

/etc/exportsのオプションのうち、rw(読み書き許可)/ro(読み取り専用)やsync/async(書き込み完了をどのタイミングでクライアントに通知するか)に加え、セキュリティ上重要なのが root_squash です。既定で有効になっており、クライアント側のrootユーザーによるアクセスを、サーバー側では権限の低い匿名ユーザー(nobody)に読み替えます。no_root_squash を指定するとこの保護が無効になるため、信頼できるホスト以外には設定すべきではありません。

NFSのバージョンによる違い: NFSv3はステートレスで、ポートマッパー(rpcbind)が複数の補助ポートを使うためファイアウォール設定が煩雑になりがちです。NFSv4はステートフルな単一プロトコルとなり、既定でTCPの2049番ポートのみで完結するほか、Kerberosを使った強固な認証(sec=krb5)にも対応します。新規構築では特別な理由がない限りNFSv4を選ぶのが一般的です。

NFSではユーザーID(UID)・グループID(GID)が数値のままネットワーク越しに伝わる点も重要です。サーバー側とクライアント側で同じUID/GIDが異なるユーザーに割り当てられていると、意図しないユーザーにファイルの所有権が見えてしまう問題が起こります。複数サーバーでNFSを使う環境では、LDAPのような仕組みでUID/GIDを一元管理し、サーバー間でズレが生じないようにするのが実務上のベストプラクティスです。

$ rpcinfo -p サーバーIP        # サーバー上で稼働しているRPCサービスとポート番号を確認(NFSv3のトラブルシューティングに有用)
   program vers proto   port  service
    100000    4   tcp    111  portmapper
    100000    3   tcp    111  portmapper
    100003    3   tcp   2049  nfs
    100003    4   tcp   2049  nfs
    100005    3   tcp  20048  mountd
    100021    4   tcp  38621  nlockmgr
$ nfsstat -c                 # クライアント側のNFS統計情報を表示
Client rpc stats:
calls      retrans    authrefrsh
128394     3          128401

Client nfs v4:
null         read         write        commit       open         close
0.00%        42.18%       11.30%       2.01%        6.44%        6.30%

この行のこの値に注目: rpcinfo -pのNFSv3環境では、portmapper(111番)に加えてnfs・mountd・nlockmgrなどが、それぞれ異なる(多くの場合ランダムな)ポート番号で待ち受けています。これがNFSv3でファイアウォール設定が煩雑になる理由です。nfsstat -cのretrans(再送回数)がcallsに対して大きい割合を占めている場合、ネットワーク品質の問題やサーバー側の応答遅延が疑われます。

/etc/exportsの主なオプション意味
rw / ro読み書き許可 / 読み取り専用
sync / async書き込みをディスクに確定させてから応答するか(sync、安全)/すぐ応答するか(async、高速だが障害時にデータ消失の可能性)
root_squash / no_root_squashクライアント側rootの権限を匿名ユーザーに読み替えるか(既定はroot_squashで有効)
all_squashrootに限らず、すべてのユーザーを匿名ユーザーに読み替える。読み取り専用の公開共有などで使用

NFSv4のディレクトリ構成とアクセス制限

NFSv4では、サーバー側で1つの「疑似ファイルシステム」のルート(fsid=0を指定したエクスポート)を頂点とし、実際に共有したいディレクトリをその配下にbindマウントする構成が一般的です。クライアントからは、この疑似ルートを基準にした相対パスでマウントします。

/etc/exports(NFSv4向けの構成例)
/export           192.168.1.0/24(rw,sync,fsid=0,no_subtree_check)
/export/share     192.168.1.0/24(rw,sync,bind)

アクセス制限は/etc/exportsで指定するホスト・サブネットの範囲に加えて、NFSサーバーがTCP Wrappers(/etc/hosts.allow・/etc/hosts.deny)にも対応している場合、portmapやmountdといったサービス名を指定して二重にアクセス制御をかけることもできます。

NFSv4のユーザー名前解決(idmapd)

NFSv3までは、ファイルの所有者情報を数値のUID/GIDのままやり取りしていましたが、NFSv4ではユーザー名@ドメイン名という文字列形式でやり取りする点が大きく異なります。この変換を担うのがrpc.idmapdデーモンで、設定は/etc/idmapd.confに記述します。

/etc/idmapd.conf の主な設定項目
[General]
Domain = example.com

[Mapping]
Nobody-User = nobody
Nobody-Group = nogroup

Domainの値がサーバー側とクライアント側で一致していないと、正しくマッピングできたはずのユーザーがnobodyとして見えてしまうというトラブルが典型的です。ファイルの所有者が急にnobodyになってしまった場合は、まずサーバーとクライアントのidmapd.confのDomain設定が一致しているかを確認します。

Kerberosを使った強固な認証(sec=krb5)

既定のNFSは、クライアントが名乗るUID/GIDをサーバー側がそのまま信用する「AUTH_SYS」という認証方式を使っており、クライアント側さえ細工すれば別のユーザーになりすませてしまう弱点があります。より強固なセキュリティが必要な環境では、Kerberosによる認証(sec=krb5)を使います。

サーバー側 /etc/exports(Kerberos認証を要求する例)
/srv/nfs/secure  192.168.1.0/24(rw,sync,sec=krb5)
クライアント側でのマウント(正常時は無出力)
$ sudo mount -t nfs4 -o sec=krb5 サーバーIP:/secure /mnt/secure

Kerberosのチケットが取得できていない状態でこのマウントを試みると、次のようなエラーになります。

$ sudo mount -t nfs4 -o sec=krb5 サーバーIP:/secure /mnt/secure
mount.nfs4: Operation not permitted

この行のこの値に注目: Operation not permittedという一見分かりにくいエラーは、sec=krb5指定時にはKerberosの本人確認チケット(kinitで取得)が必須であることが原因のことが多く、klistで有効なチケットを保持しているかをまず確認します。

secオプションの値意味
sys(既定)クライアントが名乗るUID/GIDをそのまま信用する(AUTH_SYS)
krb5Kerberosによる本人確認のみ行う
krb5i本人確認に加え、通信の完全性(改ざん検知)も保証する
krb5p本人確認・完全性に加え、通信内容自体を暗号化する(最も安全だが最もオーバーヘッドが大きい)

Kerberos認証を使うには、NFSサーバー・クライアントの双方がKerberos KDC(鍵配布センター)と連携できる状態になっている必要があり、単体のオプション追加だけでは完結しない点に注意してください。試験対策としては、sec=オプションの4段階(sys/krb5/krb5i/krb5p)でセキュリティレベルが変わることを押さえておけば十分です。

マウントオプションのチューニング

オプション意味
rsize / wsize1回の読み込み・書き込みで転送するデータサイズ。大きくすると高速化することがあるが、ネットワーク品質によっては逆効果になることも
timeo応答がない場合に再送を試みるまでのタイムアウト時間(0.1秒単位)
retrans再送を試みる回数の上限
ac / noac属性キャッシュを使うか(既定はac=使う)。noacは常に最新の状態をサーバーへ問い合わせるため、複数クライアントからの同時書き込みに強い代わりに性能は落ちる
$ sudo mount -t nfs -o rsize=32768,wsize=32768,timeo=30 サーバーIP:/data /mnt/data   # 正常時は無出力

実際にどのオプションでマウントされたかは、mountコマンド(引数なし)や/proc/mountsで確認できます。

$ mount | grep /mnt/data
サーバーIP:/data on /mnt/data type nfs (rw,relatime,vers=3,rsize=32768,wsize=32768,timeo=30,...)

この行のこの値に注目: 指定していないオプション(vers=3やrelatimeなど)もカーネル側の既定値として補完され、実際に有効になっている全オプションがここに表示されます。指定したrsize・wsize・timeoの値が意図通り反映されているかは、この出力で必ず確認します。

SambaとNFSの使い分け

状況選択
Windowsクライアントと共有したいSamba
Linux/Unixサーバー間で共有したいNFS
混在環境両方を並行して提供することも多い

マウントの動作確認とトラブルシューティング

クライアント側でNFS共有をマウントできない、あるいは急に応答がなくなった場合、まずサーバー側でその共有が正しくエクスポートされているかを確認します。

$ showmount -e サーバーIP    # サーバーが公開しているNFS共有の一覧を確認
clnt_create: RPC: Port mapper failure - Unable to receive: errno 110 (Connection timed out)
$ sudo mount -t nfs サーバーIP:/data /mnt/data
mount.nfs: Connection timed out
$ sudo exportfs -ra          # /etc/exportsの変更後、サーバー側で再エクスポート(正常時は無出力)

この行のこの値に注目: clnt_create: RPC: Port mapper failure ...やmount.nfs: Connection timed outは、いずれもサーバー側のNFS関連サービスが起動していない、あるいはファイアウォールで該当ポートが塞がれている場合に典型的に出るエラーです。この場合、サーバー側でsystemctl status nfs-kernel-serverやrpcinfo -pで稼働状況を確認し、続いてexportfs -raで/etc/exportsの内容を再反映してから、クライアント側で再度マウントを試みるという切り分け手順になります。

NFSは既定で「hard」マウント(サーバーが応答するまで処理をブロックし続ける)になっており、サーバー障害時にクライアント側のプロセスがハングしたように見えることがあります。応答性を優先したい一部の用途では、タイムアウト時にエラーを返す「soft」マウントを選ぶこともありますが、書き込み中のデータ破損リスクとのトレードオフがあるため、用途に応じて慎重に選択する必要があります。

永続的なマウント設定と自動マウント

再起動後もNFS共有を自動的にマウントしたい場合は、/etc/fstabに記述するのが基本です。ただしNFSサーバーがネットワーク越しに存在するという性質上、ローカルディスクとは違った注意点があります。

サーバーIP:/data  /mnt/data  nfs  defaults,_netdev  0  0

_netdevオプションは「ネットワークが利用可能になってからマウントを試みる」ことをシステムに伝えるもので、これを付けないとネットワークインターフェースが起動しきる前にマウントが試みられて失敗する場合があります。常時接続とは限らないリモート共有では、第4章で扱ったautofsによるオンデマンドマウントを使う方が、サーバー側の一時的な不調がクライアントの起動プロセス全体を止めてしまうリスクを避けられ、より堅牢な構成になることもあります。

確認クイズ

Q1. NFSサーバー側で、共有するディレクトリと許可するクライアントを定義するファイルはどれですか?

解説: /etc/exports にNFSで共有するディレクトリと、アクセスを許可するクライアントの範囲・オプションを記述します。

Q2. NFSv4で標準的に使われるポート番号はどれですか?

解説: NFSv4はステートフルな単一プロトコルとなり、既定でTCPの2049番ポートのみで完結します。NFSv3はポートマッパーが複数の補助ポートを使うため、ファイアウォール設定が煩雑になりがちです。

Q3. クライアント側rootユーザーの権限を、サーバー側で匿名ユーザーに読み替える既定の動作を何と呼びますか?

解説: root_squashは既定で有効になっており、クライアント側rootによるアクセスをサーバー側では権限の低い匿名ユーザー(nobody)に読み替えます。

Q4. 設定ファイル/etc/fstabにNFS共有を記述する際、ネットワークが利用可能になってからマウントを試みるよう指定するオプションはどれですか?

解説: _netdevオプションを付けることで、ネットワークインターフェースが起動する前にマウントが試みられて失敗する事態を防げます。

Q5. NFSv4でファイルの所有者情報をユーザー名@ドメイン名の文字列形式でやり取りするために必要なデーモンはどれですか?

解説: rpc.idmapdは、NFSv4でのユーザー名文字列とローカルのUID/GIDとの変換を担うデーモンで、/etc/idmapd.confのDomain設定がサーバー・クライアント間で一致している必要があります。

Q6. NFSのマウントオプションのうち、常に最新の状態をサーバーへ問い合わせることで複数クライアントからの同時書き込みに強くする代わりに性能が落ちるものはどれですか?

解説: noacは属性キャッシュを使わない設定で、常に最新の状態をサーバーに問い合わせるため一貫性は高まりますが、性能は低下します。

Q7. sec=オプションのうち、本人確認・通信の完全性検証に加えて通信内容自体を暗号化する、最も安全なレベルはどれですか?

解説: krb5pは本人確認・完全性検証・通信内容の暗号化のすべてを行う、最もセキュリティレベルの高い設定です。