NFSv4サーバーの作り方

検証環境

セキュリティ

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

専用NIC(VLAN)割り当て

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

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

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

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

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

結論

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

セットアップ

ZFS領域確保(作業例)

sysctl vfs.zfs.min_auto_ashift=12
zpool create -O atime=off export /dev/da1

/boot/loader.conf(環境依存)

vfs.zfs.trim.enabled="0"

※検証環境に使用した VMware ESXi 6.0U2 上(5.5/5.5U1/5.5U2/6.0/6.0U1 でも確認、いずれも LSI Logic SAS アダプタによる)では TRIM/UNMAP がエラーになってログがウザいので ZFS TRIM 機能をオフにする。

物理環境下なら今時のHDDであれば TRIM/UNMAP 試してエラーになることは無いと思われるので、CAMのエラーメッセージがうるさい時だけ設定する。

どういうエラーメッセージが表示されるかというと、下記のようなメッセージ(SCSI/SAS なんでの TRIM というよりは UNMAP が実行された)で3回リトライするので、下記のメッセージが3回続く。

(da1:mpt1:0:0:0): UNMAP. CDB: 42 00 00 00 00 00 00 00 18 00
(da1:mpt1:0:0:0): CAM status: SCSI Status Error
(da1:mpt1:0:0:0): SCSI status: Check Condition
(da1:mpt1:0:0:0): SCSI sense: Vendor Specific asc:0,0 (No additional sense information)
(da1:mpt1:0:0:0): Error 5, Unretryable error

/etc/rc.conf(NICチューニング)

ifconfig_インターフェース="inet XXX.XXX.XXX.XXX netmask XXX.XXX.XXX.XXX mtu 9000"

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

なお手動で設定できるが、その場合、MTU値を反映するために一度、下記のようにインターフェースをダウンさせる必要がある。

ifconfig インターフェース mtu 9000
ifconfig インターフェース down
ifconfig インターフェース up

/etc/sysctl.conf

NFSの最低利用バージョンの指定

vfs.nfsd.server_min_nfsvers=4

なお最大利用バージョンの指定は rc.conf 中の「nfsv4_server_enable="YES"」設定で行われている。

ZFSのチューニング

vfs.zfs.min_auto_ashift=12
vfs.zfs.vdev.async_write_max_active=31

特に async_write_max_active はドライブが対応しているNCQ・TCQの数(-1)を指定する(台数があれば台数分を乗算する)。

NFSのチューニング(未検証)

vfs.nfsd.issue_delegations=0
vfs.nfsd.enable_locallocks=0

vfs.nfsd.issue_delegations

vfs.nfsd.enable_locallocks

/etc/exports

V4: /export -network ネットワークアドレス -mask ネットマスク

とりあえず、/export がNFSv4共有できるようになる。ただし、/export 自体は sharenfs=off なので、どこからからもマウントできない(厳密にはできるけどアクセスできない)。

/etc/rc.conf

rpcbind_enable="YES"
nfsuserd_enable="YES"
mountd_enable="YES"
nfs_server_enable="YES"
nfsv4_server_enable="YES"

rpcbind_flags="-h 公開するNFSサーバーのIPアドレス"
nfsuserd_flags="-domain アカウント識別用ドメイン"
mountd_flags="-l -h 公開するNFSサーバーのIPアドレス"
nfs_server_flags="-t -h 公開するNFSサーバーのIPアドレス"

このうち、nfsuserd_flags で指定する「ドメイン」の指定が重要となる。 NFSv4では、NFSサーバーとNFSクライアント間のユーザー識別子を「ユーザー@ドメイン」で識別するため、合わせておく必要がある。

これは厳密にはサーバーのドメインとは別物であるため、別途決め打ちする必要がある。

アカウント作成

アカウント作成例

pw groupadd postgres -g 5432
pw useradd  postgres -u 5432 -g postgres -c "postgres" -s /usr/sbin/nologin
install -d -o postgres -g postgres -m 0755 /home/postgres

※FreeBSD の PostgreSQL 用アカウントとして pgsql (/usr/ports/UIDs ファイル参照のこと)があるが、CentOS の PostgreSQL 用アカウント(postgres)とはマッチしないので、別途作成する。

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

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

領域の共有設定

共有設定

/export をどう共有するかによるが「/export/NFSv4クライアント名」として、クライアント単位で共有設定する場合は、下記のようにパーティションを切る。

zfs create -o sharenfs="-maproot=root NFSクライアントIP" export/NFSクライアント名

sharenfs 設定を行うと、/etc/zfs/exports ファイルに掃き出されるのと、合わせてmountd(8)に再読み込み(HUP シグナル)が実施される。

一つの領域を複数のNFSクライアント間で共有するなら、/etc/exports に集約するのが良いと思われ(未実験)。

なおNFSクライアントからは、「/NFSクライアント名」でマウントすることになる(/export がトップディレクトリとなって見えなくなる)。

更にお好みに応じて、exec=off、setuid=off も追加しよう。これはNFSサーバーとしてはこれら属性を「解釈しない」という意味であって、NFSクライアントはNFSクライアントで、別途設定が必要となる。

設定確認

mountd(8) 再読み込みによりNFSクライアントからマウントできるようになるわけだが、これが成功したのか失敗したのかはよくわからない。 そこで、「showmount -e」コマンドと「zfs get sharenfs」コマンドの実行結果を見比べて判断すること(設定した内容が反映されてないなど)。

showmount -e
zfs get sharenfs

参考文献