FreeBSD ZFS で Samba



FreeBSD はファイルシステムに ZFS (OpenZFS) を採用。ZFS は Windows NTFS とほぼ同じ NFSv4 ACL を採用している。

UNIX 側のアクセス権限をそのまま Samba で使う方法について。

仕様

NFSv4 (NFSv4.0), NFSv4.1 および NFSv4.2 がある。Windows NTFS ACLは NFSv4.1 とほぼ同じ。

NFSv4 ACL と Windows NTFS ACLs との差異: ACLs - Linux NFS

The two ACL models are essentially the same, with some minor differences:

  • Windows does not have the special owner, group or everyone principals in ACEs. You could handle owner and group ACEs by translating them to ACEs that refer explicitly to the current owner or group, but the result won't behave correctly under chown().
  • RFC3530 says that if an ACL neither allows nor denies a certain mode bit, then behavior is undefined. But users of Windows ACLs expect them to deny by default. (I believe NFSv4 is now specified to have Windows behavior in RFC3530bis and RFC5661?)
  • Windows documentation suggests that if some but not all requested access bits have been allowed, then DENY aces will still apply even if they only deny bits among those already allowed. This has the somewhat bizarre result that an ACL can allow certain permissions individually but deny them in combination. The NFSv4 ACL algorithm doesn't have this property. (We're waiting the results of experiments to confirm this property of Windows ACLs.)

A bigger (and perhaps more important!) difference is in the way ACEs refer to users--NFSv4 uses string names of the form user@domain, Windows uses SIDs--but we're ignoring the name-mapping issue for now.

FreeBSD 13 のZFS は NFSv4.0 レベルに留まるようだ。NFSv4.1 への取組みはこの辺; D26028 Expose NFSv41 ACL automatic inheritance flags

いろいろなファイルシステムでの実装状況

Linux 以外は, NFSv4 ベースがむしろ主流. Linux と HP-UX (?) だけがドラフトPOSIX モデルに留まっている。

  • FreeBSD は ZFS (OpenZFS実装) が NFSv4 だけを利用. ドラフトPOSIX モデルは利用不可。UFS では逆にドラフトPOSIX のみ。
  • Oracle Solaris も ZFS (OpenZFS とは互換性なし.) で NFSv4 を利用. Oracle Solaris ACL モデル. chmod コマンドと ls コマンドで ACL を設定および表示する。
  • ストレージソフトウェア IBM Spectrum Scale [旧 IBM General Parallel File System (GPFS)] は NFSv4 ACLをベースに, SMB Security Descriptor と相互マップを提供。 Authorizing file protocol users - IBM Documentation
  • AIX の JFS2 ファイルシステム (Linux の JFS とは互換性なし.) も NFSv4 ACLをサポート。古い AIXC ACL もサポート。

macOS は確かでない。Mac OS X v10.4 Tiger [2005年] で ACLs が導入されたが, この機能性はよく分からなかった。その後, 2017年 macOS High Sierra 10.13 で新しい Apple File System (APFS) が導入されたが, これは NFSv4ベース, か? ただ, APFS は iOS でも導入されているが, iOS は ACLs をサポートしない。

Windows と FreeBSD の挙動

Windows エクスプローラ, FreeBSD setfacl コマンド

Windows で新しくフォルダを作ると, アクセス権は, すべて上のフォルダから継承されてくる。かつ, 適用先は「このフォルダー、サブフォルダーおよびファイル」になる (子に継承されていく)。

ファイルを作成すると, フォルダと同じアクセス許可になる。

フォルダのアクセス権を変更するときは, [セキュリティの詳細設定] ダイアログの [継承の無効化] ボタンで, 親との継承を切れる。⇒ "継承元" 列が "なし" になる。

所有者 owner を個人ではなく, 任意のセキュリティグループとすることもできる。

アクセス許可は, ファイル/ディレクトリの所有者でなくても, 書き込み権限があれば変更できる。

適用先を「このフォルダー、サブフォルダーおよびファイル」にして、子孫フォルダおよびそのファイルまで継承させることができる。ただ、再帰的にエクスプローラが書き込んでいるようにみえる。

他方, FreeBSD 13.0 は次のようになっている:

NFSv4 ACL の更新・表示は setfacl コマンド, getfacl コマンドを使う。

chmod コマンドで伝統的パーミション (ファイルモード) を変更すると, NFSv4 ACL は消える。マジか・・・ ⇒ これは初期状態。ZFSファイルシステムの設定による (aclmode).

親でアクセス許可に継承フラグを付けていても、子のほうで継承を切れるのは同じ。

ファイル/ディレクトリのACL が、複数の許可エントリ (ACE) から構成されるのも同じ。例えば次のように書く;

# setfacl -m g:sales:full_set:fd:allow f1-by-sato

-m オプションで許可エントリを与える。エントリはコロンで区切る。読み方は, (1) tag type = グループ, (2) グループ名 sales, (3) パーミション = フルコントロール, (4) 子に継承させる, (5) entry type allow or deny. エントリごとに許可か拒否を選ぶのも同じ。拒否のACE のほうが優先される。

親フォルダのほうに「子に継承させる」フラグを付けたとしても、setfacl コマンドでは既存の子フォルダにこの許可エントリがコピーされるわけではない。それって継承してないやん・・・

新しく子フォルダを作った場合は、許可エントリが自動的にコピーされる。ただし, "アクセス許可の変更" と "所有権の取得" が off になる。⇒ これは ZFSファイルシステムの設定 (aclinherit)。後述する。

勝手に owner@, group@everyone@ が追加されるので、親から継承する Everyone とダブってしまう。⇒ ZFSファイルシステムの設定と Samba zfsacl:block_special の合わせ技で対応。

ACEエントリを削除するには次のようにする;

# setfacl -x everyone@::fdI:allow f1-by-sato

[このオブジェクトの親からの継承可能なアクセス許可を含める]チェックボックス

親フォルダから自動的に引っ張ってくるのは、そのオブジェクト自身の許可エントリではないから、ACEのフラグではなくて ACL のフラグ。

Windows の ACLデータの構造: SelfADSI : Active Directory Permissions : Security Descriptors データ型のリファレンス: [MS-DTYP]: Windows Data Types

セキュリティデスクリプタ header のフラグ:

DACL_AUTO_INHERITED
DACL_PROTECTED
dacl_protected ビットが設定されている場合、Windows オペレーティング・システムに対して、「このオブジェクトの親からの継承可能な許可を含める」チェック・ボックスがクリアされていることを示します。dacl_protected ビットがクリアされている場合、現行ファイルとその親ディレクトリーの ACL は、「このオブジェクトの親からの継承可能な許可を含める」チェック・ボックスの状態を判別します。 https://www.ibm.com/docs/ja/flashsystem-v7000u/1.6.2?topic=lists-controlling-inheritance-entries-inside-acl

これらのフラグは NFSv4.1 で定義されており, FreeBSD 13 ZFS ではまだ未対応。Samba のほうで手当する。

   const ACL4_AUTO_INHERIT         = 0x00000001;
   const ACL4_PROTECTED            = 0x00000002;
   const ACL4_DEFAULTED            = 0x00000004;

FreeBSD Samba設定

FreeBSD 13.0, Samba 4.12 で試した。

ZFS設定

この設定をしないと、Windows と整合する挙動にできない。これがキモ。

# zfs set aclmode=passthrough zroot
# zfs set aclinherit=passthrough zroot

ZFS snapshot 機能も使えるが、Samba設定については, 例えばこの辺を参照; Daniel Washburn | FreeBSD + Samba 4 + ZFS Recipe

smb.conf ファイル

sambaパッケージは, バージョンごとに分かれている。

# pkg search samba
p5-Samba-LDAP-0.05_2           Manage a Samba PDC with an LDAP Backend
p5-Samba-SIDhelper-0.0.0_3     Create SIDs based on G/UIDs
samba-nsupdate-9.16.5          nsupdate utility with the GSS-TSIG support
samba411-4.11.15_1             Free SMB/CIFS and AD/DC server and client for Unix
samba412-4.12.14               Free SMB/CIFS and AD/DC server and client for Unix
samba413-4.13.7                Free SMB/CIFS and AD/DC server and client for Unix

設定ファイルは /usr/local/etc/smb4.conf ファイル. この場所で決め打ち。smb.conf ではない。

この例では, できるだけデフォルト値にする。最小限の例を示すため, LDAP も使わない。Active Directory も使わない。パスワード同期なども使わない。

古い解説では nfs4:mode = special が多いが、それは廃れた。"simple" の場合, ZFS の owner@, group@ は, Windows Well-known SID Creator Owner, Creator Group にマップされる。

[global]
    ;;unix charset = UTF-8

    # A standalone file server or a DC.
    security = user

    # クライアントとのプロトコル #######################################
    min protocol = SMB3

    # CIFS UNIX extensions は無効にすること。これが yes の場合, `wide links` は
    # 自動的に disable になる.
    unix extensions = no

[share]
    # no で疎なファイル sparse file を扱える
    strict allocate = no
    
    path = /home/samba/share
    writable = yes 

    # ZFS / NFSv4 ##########################################
    # `acl_xattr` とは両立しない.
    vfs objects = zfsacl streams_xattr

    # simple (既定値) -
    # special (非推奨) - 廃れた.
    nfs4: mode = simple

    # dontcare (既定値) -
    # merge             - 重複するACEフラグとACEマスクを ビット OR する
    nfs4: acedup = merge

    # no (default) -
    # yes          - FreeBSD workaround.
    #                NFSv4.0 ACE4_INHERITED_ACE 親ディレクトリからの継承
    #                がない場合, NFSv4.1 ACL4_PROTECTED が指定されたとみなす
    # `map acl inherit` を使うほうがよい。
    ;;zfsacl:map_dacl_protected = [yes|no]

    # これを明記しているケースは見当たらない。
    ;;zfsacl:block_special = yes

    # 属性 / ACL関係 ######################################
    
    # DOS attributes (System, Hidden, Archive or Read-Only) をUNIX 側の拡張
    # 属性に保存.
    store dos attributes = yes
    # ドキュメントでは store dos attributes = yes により自動的に off になると
    # あるが, 明示的に off が必要。
    map archive = no

    # no (default) - file/directory の owner のみがパーミションを変更できる
    #                UNIX流
    # yes          - write access を持つユーザは変更可. Windows流.
    # `acl_xattr` or `acl_tdb` を使う場合は自動的に on.
    dos filemode = yes

    # no (default) -
    # このオプションを有効にすると, unix mode が 0777 になる。NFSv4モデルには
    # 合わない.
    # VFS module `acl_xattr` or `acl_tdb` を使う場合, このオプションは自動的に
    # on になる.
    #inherit acls = yes

    # no (default) -
    # yes          - 'inherit' または 'protected' アクセス制御を UNIX 側の拡張
    #                属性に保存。
    map acl inherit = yes

zfsacl vfsモジュールがキモ。zfsacl:map_dacl_protected は使わない。見做す、はよくない。Samba 機能の map acl inherit を使ったほうがよい。

ファイルの作成者が owner になるので, dos filemode = yes でないと, Windows から見たときにすごい不自然になる。共有フォルダのユーザにアクセス権限を変更させない運用にしたいときは no か。

起動

起動。おっと! /etc/rc.conf ファイルに追加。

# /usr/local/etc/rc.d/samba_server start
Cannot 'start' samba_server. Set samba_server_enable to YES in /etc/rc.conf or use 'onestart' instead of 'start'.

Reload するには次のようにする;

# service samba_server reload

試す

ユーザをいっぱい作る。LDAP + PAM, パスワード同期などは使わず、とりあえず UNIX と Samba の両方で手作業。

FreeBSD でユーザを作る;

# adduser

対話式に6名作る. sato, tanaka, sasada, takahashi, kobayashi, miyake

グループを作って、ユーザを追加する。

# pw groupadd sales
# pw groupadd admin

# pw groupmod sales -M sato,tanaka,sasada
# pw groupmod admin -M takahashi,kobayashi,miyake

UNIX 側は getent コマンドで確認できる。

Samba でも追加. 一人ずつしか追加できない。面倒.

pdbedit -a sato

登録完了。次のようになった。

pdbedit --list
sato:1002:Sato (Sales)
sasada:1004:Sasada (Sales)
kobayashi:1006:Kobayashi (Admin)
tanaka:1003:Tanaka (Sales)
takahashi:1005:Takahashi (Admin)
miyake:1007:Miyake (Admin)

グループの mapping を作る. net コマンドを使う。

# net groupmap add unixgroup=sales ntgroup=sales
# net groupmap add unixgroup=admin ntgroup=admin

UNIX グループとWindowsグループの間のマッピングは透過的で, 所属ユーザはそのまま利用される。逆に、LDAP などを使わないと、Windows 側からグループに含まれるユーザを変更できない。

Windows側の設定

C:\Windows\System32\drivers\etc\hosts ファイルに Samba サーバのIPアドレスを追加。DNS設定でもいけそうだが?

テストのためにユーザを切り替えるには, net use コマンドの /delete オプションで接続を解除できる。

>net use \\mango.fruits\IPC$ /delete
\\mango.fruits\IPC$ が削除されました。

これだけでは接続情報がクリアされないことがある。klist コマンドでクリアされる。

リンク

Oracle Solaris ACL モデル - Oracle® Solaris 11.3 での ZFS ファイルシステムの管理