l
l
Apache 2.4系でHTTP/2サーバを構築してみるテスト。
FreeBSDのZFSのACLを設定してみる。従来、UNIX系のOSでは、UNIXファイルシステム(UFS)の「モード」と呼ばれる形式によって、ファイルのアクセス権限を管理していました。 ところが、ZFSでは、「モード」に加えて、アクセスコントロールリスト(ACL)と呼ばれる新しい形式で、ファイルのアクセス権限を管理します。 最初に、ACLを確認するためのgefaclコマンドの使い方を確認し、次にUFSの「モード」を確認します。 その後、ACLの読み方と、setfaclコマンドによる設定の仕方を見ていきます。 最後に、UFSの「モード」では表現できない、ZFSのACLがある場合、chmodコマンドが、「Operation not permitted」と出力して失敗するケースを説明します。 まだの方は、まず、下のリンクからZFSの初期設定を行ってください。 参考 >> FreeBSDでZFSを設定してみる。
なお、ZFSのオリジナルは、今では知らない人の方が多い気もするSolarisとよばれるUNIX系OSですが、Solarisでは、「ls」コマンド及び、「chmod」コマンドを、ACLに対応させる拡張が行われているので、このページに記載のコマンド例は動きません。 FreeBSD(とたぶんLinux)でZFSをお使いの方に限定の説明です。
getfaclコマンドの使い方まず、ZFSをマウントしているディレクトリの配下にcdコマンドで移動します。 $ cd /tank/home/username 次に、今回の例で使うディレクトリを作ります。名前は何でもいいのですが、ここでは、「sample」としてみます。 $ mkdir sample さっそく、作ったディレクトリのACL(アクセス権限リスト)を確認してみます。 $ getfacl sample # file: sample ←ファイル名/ディレクトリ名(ディレクトリエントリ名) # owner: root ←ディレクトリエントリの所有者 # group: wheel ←ディレクトリエントリのグループ owner@:rwxp--aARWcCos:-------:allow ←所有者のアクセス権限 group@:r-x---a-R-c--s:-------:allow ←グループに所属している人のアクセス権限 everyone@:r-x---a-R-c--s:-------:allow ←上記以外のユーザ、グループのアクセス権限 最初の行に、ファイル名かディレクトリ名が出力されます。 ファイルやディレクトリをまとめて、「ディレクトリエントリ」と呼びます。 次の行に、ディレクトリエントリの所有者、続いてグループが表示されます。 最後に、ACLエントリ(アクセス権限)が1行ずつ並びます。 ACLエントリの1行は、「:」(コロン)で区切られています。左から、ACLタグ、ACL修飾子、ACL継承フラグ、ACLタイプの順番です。 出力の4行目の「owner@」がACLタグ、「rwxp--aARWcCos」がACL修飾子、「------」がACL継承フラグ、「allow」がACLタイプです。 これを理解するためには、まずUNIXファイルシステム(UFS)を理解しておくことが重要です。
UNIXファイルシステム(UFS)の「モード(mode)」の復習そこで、ACLを説明する前に、まず、UNIXファイルシステム(UFS)の「モード」の仕組みを軽く振り返ってみます。 UNIXファイルシステムのファイルやディレクトリ(ディレクトリエントリ)には、ユーザIDとグループIDを一つずつ設定できます。 ユーザIDとグループIDは必須で、一つのディレクトリエントリに、必ず一つずつユーザIDとグループIDが設定されます。
この2つのIDを使って利用者を3つに分類します。 ユーザIDのユーザを「所有者」、グループIDのグループに所属している「グループ所属者」、所有者でもグループ所属者でもない、「その他」の3つです。 この3つに分類された「所有者」「グループ所属者」「その他」のそれぞれの対象者に、権限を許可したり禁止したりします。
具体的には、権限の対象者をwhoシンボルと呼ばれる文字で示し、権限の内容をpermシンボルと呼ばれる文字で示します。 whoシンボルとpermシンボルの間には「+」や「-」のopシンボル(オペレータシンボル)を入れて、許可するのか、禁止するかを指定します。 例えば「u+x」は所有者にファイルの実行を許可します。「g-w」はグループ所属者の書き込みを禁止します。 これらをchmodコマンドに指定する事で、既存のファイルやディレクトリに対する権限を指定します。
既存のディレクトリエントリに対する権限(モード)の設定chmodコマンドは、既存のファイルやディレクトリの「モード」と呼ばれるアクセス権を設定するためのコマンドです。 chmodコマンドの書式
chmod [whoシンボル][opシンボル][permシンボル] [filename] 下記の例では、「u+x」は所有者にファイルの実行を許可します。 $ chmod u+x sample 「g-w」はグループ所属者の書き込みを禁止します。 $ chmod g-w sample この方法では、所有者だけに権限を追加したり、グループだけに書き込みを禁止したりと言った、一部の対象者に対する差分の権限を指定していますが、全員の権限を一気に設定する方法もあります。 chmodコマンドの書式
chmod [モード] [filename] これは、permシンボルの権限を数値化して、r:「読み込み」を4、w:「書き込み」を2、x:「実行」を1として、許可する権限の合計を、所有者、グループ、その他の順番に並べたものです。 これをファイルの「モード」と呼びます。 例えば、 $ chmod 755 sample の755の内、先頭の7は「所有者」の「読み込み(4)」+「書き込み(2)」+「実行(1)」の合計で、フルアクセスを許可します。 続く5が、「グループ」への「読み込み(4)」+「実行(1)」の許可、 最後の5が、「その他」への「読み込み(4)」+「実行(1)」の許可になります。 この「755」が「モード」と呼ばれるアクセス権限を示すデータになります。 もう一つ例を挙げると、 $ chmod 700 sample とすれば、「所有者」だけがフルアクセス、「グループ」と「その他」は何もできなくなります。 この「700」の部分が、ファイルの「モード」と呼ばれるデータになります。
上の表にあるとおり、「モード」には、「ACL」で表現可能な部分と、不可能な部分があります。 逆に「ACL」は、「モード」にはない柔軟性で、アクセス権限を指定できます。 この違いがセキュリティー上の問題となることがありますが、後述の通り、ZFSでは、ZFSのaclinheritプロパティーと、aclmodeプロパティーの値で、初期状態では問題が起きないようになっています。
新規のディレクトリエントリに対する権限(モード)の設定chmodコマンドは、既存のファイルやディレクトリに設定された、アクセス権限(モード)を設定できました。 それでは、新規にファイルやディレクトリを作った場合の、「モード」はどうなるのでしょうか? 新規にファイルやディレクトリを作った場合の「モード」は、「umask」と呼ばれる数値を元に決定します。 それを説明する前に、新規にファイルやディレクトリを作ったときに、設定されていると便利な「モード」を考えてみます。
ディレクトリを作った場合、実行権限が付かなければ、検索ができなかったり、cdコマンドでディレクトリの中に入ることができなくなり不便です。 そのため、新規のディレクトリには、「755」といったモードを設定すると、不便無く使えそうです。 一方、ディレクトリのように、ファイルにいきなり実行権限が付くと、何でもかんでも実行できることになってしまい困ったことになりそうです。 つまり、新規のファイルには、「644」といったモードを設定したいところです。
このように、ファイルとディレクトリでは、異なるモードが設定されると、便利です。 これを一つの値で実現するのが、umaskとなります。 umaskには、許可したくない(禁止したい)権限を、モードのように列挙します。 7だと全てを禁止、2だと書き込みを禁止、0だと何も禁止しません。 たとえば、所有者には何も禁止せず、グループとその他には書き込みを禁止する場合、「022」をumaskに設定します。
このumaskの数値と、ファイルの初期モード「666」、もしくはディレクトリの初期モード「777」の論理積(AND演算)を行います。 umaskのmaskとは、「AND演算」のことですね。 ファイルを作ると、モード「666」と、umask「022」のAND演算の結果、モード「644」が設定されます。 一方、ディレクトリを作ると、モード「777」と、umask「022」のAND演算の結果、モード「755」が設定されます。 ちなみに、umaskに027を設定しておけば、新しく作るディレクトリ(750)、ファイル(640)ともに、「その他」の人が見られなくなります。 この仕組みによって、禁止したい権限をumaskに設定すれば、新しいファイル、新しいディレクトリのそれぞれに、ふさわしい「モード」を設定できます。
さきほどの表にあるように、「モード」と「ACL」には、双方に真似ができない違いがあるため、厳密な表現では無いのですが、ZFSにおいて、chmodコマンドに相当するのが「setfaclコマンド」で、umaskに相当するのが「ACL継承フラグ」になります。
ACLエントリの構成さて本題に戻ります。先ほども説明したとおり、ACLエントリは、 [ACLタグ]:[ACL修飾子]:[ACL継承フラグ]:[ACLタイプ] のように4つのパートに分かれています。 owner@:rwxp--aARWcCos:-------:allow group@:r-x---a-R-c--s:-------:allow everyone@:r-x---a-R-c--s:-------:allow ACLタグ(ACL tag)ACLエントリの先頭にはACLタグと呼ばれる情報が表示されます。 ACLタグとは、ユーザ名、グループ名のいずれかです。 上記例では、UNIXファイルシステムとの互換性のために用意された、「owner@」(所有者に相当)、「group@」(グループに相当)、「everyone@」(その他に相当)の3つのACLタグが表示されています。
ACL修飾子(ACL qualifier)ACL修飾子は、実際の権限を表現したデータです。 ACL修飾子によって表現されたアクセス権限が許可(allow)されるか、拒否(deny)されるかは、後述の「ACLタイプ」で決まります。 以下の14個の権限があります。OSやZFSのバージョンによっては実装されていない権限もあります。
ここで注意してほしいのは、ディレクトリ専用の「D」です。 配下のファイルおよびサブディレクトリを削除するアクセス権が、親ディレクトリにつくことがあります。
つまり、削除対象のファイルのやディレクトリの削除権限「d」を持っていなくても、対象を削除できる組み合わせがあります。 同じく、親ディレクトリに「wx」のアクセス権があると、「D」と同じ効果となります。
なお、-vオプションを付けると、以下のように上の表のLongの応答が表示されるので、少しわかりやすくなります。 $ getfacl -v sample # file: sample # owner: root # group: wheel owner@:read_data/write_data/execute/append_data/read_attributes/write_attributes/read_xattr/write_xattr/read_acl/write_acl/write_owner/synchronize::allow group@:read_data/execute/read_attributes/read_xattr/read_acl/synchronize::allow everyone@:read_data/execute/read_attributes/read_xattr/read_acl/synchronize::allow ちょっと長いですが、読めばわかるので安心ですね。
ACL継承フラグ(ACL inheritance flags)ACL継承フラグは、あるディレクトリで、新しく作ったファイルやサブディレクトリに、適用される当該ディレクトリのACLエントリを指定します。
ACL継承フラグの実際の動作は、セキュリティー上のリスクを避けるため、後述のZFSのaclinheritプロパティーと、aclmodeプロパティーの影響を受けます。
ACLタイプ(ACL type)ACLタイプは、ACL修飾子で指定された権限について、許可するか、拒否するかを指定します。 ACLは上から順番に評価されます。 まず、ファイルを操作しているユーザのIDが、ACLタグに含まれるか判断します。 ユーザのIDが、ACLタグに含まれていた場合、ACL修飾子にユーザのファイル操作についてのアクセス権限が含まれているか判断します。 アクセス権限も含まれていた場合、ACLタイプに従って、「許可」ないし「禁止」を判断します。 ACLタグにユーザIDが含まれていなかったり、ACL修飾子にアクセス権限が含まれていなかった場合、次のACLエントリを評価します。 こうして、全てを含むACLエントリが見つかるまで繰り返します。
ちなみに、所有者には、たとえACLタイプで、拒否(deny)されていたとしても read_acl, write_acl, read_attributes, write_attributes の各権限が与えられます。 そのため、たとえ、aclinheritプロパティーが「restricted」になっていて、新しく作ったファイルのACLに、所有者のwrite_aclが削られたとしても、所有者はACLの変更ができます。
ZFSのaclinheritプロパティーと、aclmodeプロパティーZFSでは、これまで説明してきた「ACL」と「モード」の両方を共存できます。 しかし共存できるということは、chmodで「モード」を設定したけつもりだけど、chmodから設定できない「ACL」が残っていて、意図しない人にアクセスを許してしまうといった、セキュリティー上の問題が発生します。 これを防ぐため、ZFSのデフォルトでは、chmodコマンドを実行するとchmodコマンドから設定できる「モード」と関係の無い「ACL」が、削除される設定になっています。 ACLを知らない人がいても安全になるような配慮ですが、これはこれで、設定した「ACL」が消えて、やはり意図したとおりのアクセス権限となりません。 そこで、新規のファイルやディレクトリを作るときのumaskの動作と、ZFSのACLとの整合性を取るための「aclinheritプロパティー」と、chmodコマンドにおけるZFSのACLの扱いを決める「aclmodeプロパティー」が用意されています。
aclinheritプロパティーaclinheritプロパティーは、ファイルやディレクトリーを作った場合の、ACL継承の動作を決めます。 $ zfs get aclinherit /tank/home/username NAME PROPERTY VALUE SOURCE tank/home/username aclinherit restricted default 上記の例にあるようにデフォルトでは、aclinheritがrestrictedに設定されています。 aclinheritプロパティーには、以下の値を入れることができます。
aclmodeプロパティーaclmodeプロパティーは、chmodを使った場合に、ACLをどうするか指定します。 $ zfs get aclmode /tank/home/username NAME PROPERTY VALUE SOURCE tank/home/username aclmode discard default 上の例にあるように、デフォルトでは、aclmodeがdiscardに、設定されています。 aclmodeプロパティーには、以下の値を入れることができます。
デフォルトでは、discardが設定されていますが、これではchmodコマンドを使う度に、せっかく設定したACLが削除されることになってしまい、使いにくい状態です。 「discard」は、ACLを知らない人が居る場合には有用かもしれませんが、ACLが突然消える可能性もあります。 そこで、「restricted」にしておくと、特定のchmodを実行するためには、「モード」の表現可能範囲を超えたACLを、あらかじめ手動で消しておく必要があるため、ACLが突然消えることが無くなります。 ひととおり理解したのなら、aclmodeプロパティーを、restrictedに変更しておきましょう。 なおZFSのプロパティーはデータセット毎(つまりマウントポイント毎)に設定します。 データセットとは、zfs listコマンドで表示される1行のことです。 今回は、以下のようなデータセットがある場合を例に考えます。 # zfs list NAME USED AVAIL REFER MOUNTPOINT tank 2.87G 120G 8.84M /tank tank/home 468M 120G 19K /tank/home tank/home/username 468M 120G 468M /tank/home/username データセット名が、「tank/home/username 」(マウントポイントで言うと、 /tank/home/username)のプロパティーを変える場合、下のようにコマンドを打って、プロパティの中身を確認し、 # zfs get aclmode /tank/home/username NAME PROPERTY VALUE SOURCE tank/home/username aclmode discard default aclmodeが、デフォルトの「discard」になっていたら、さらに以下のようにコマンドを打って、プロパティーを書き換えます。 このとき、zfs setコマンドの最後に指定するのは、先頭に/(スラッシュ)が無い「データセット名」です。マウントポイントではエラーになるので注意してください。 # zfs set aclmode=restricted tank/home/username 最後に、確認します。 # zfs get aclmode /tank/home/username NAME PROPERTY VALUE SOURCE tank/home/username aclmode restricted local 「restricted」となっていることを確認します。
setfaclコマンドの使い方簡単に、setfaclコマンドの使い方を説明します。 今回は、以下のような「sample」ディレクトリを例にします。 $ getfacl sample/ # file: sample/ # owner: username # group: wheel owner@:rwxp--aARWcCos:-------:allow group@:r-x---a-R-c--s:-------:allow everyone@:r-x---a-R-c--s:-------:allow この例では、ACLエントリID=0にowner(ファイル「mode」の「所有者」)、ACLエントリID=1にgroup(ファイル「mode」の「グループ」)、ACLエントリID=2にeveryone(ファイル「mode」の「その他」)のACLエントリが存在しています。
ACLエントリの追加このディレクトリに、もう一人(便宜上「another」さんとします。)だけ、フルコントロールできる人を追加したい場合を考えます。 この人は、groupやeveryoneよりも先に評価されたいACLエントリです。 つまり、ACLエントリIDの1の前に、追加したいので 「-aオプション」の後ろに、1を入れます。 続いて、ユーザを意味する「u:」とユーザ名(「another」さん)を入れます。 その後、ACL修飾子を入れますが、ACL修飾子は14文字のアルファベットなので、毎回打ち込むのはちょっと苦行です。 そこで、ACL修飾子の代わりに、ACLセットと呼ばれる、ACL修飾子の別名を入れることができます。 今回は、「フルコントロール」を意味するACLセット、「:full_set」と、ACL継承フラグに何も設定しないことを意味する「::」を続けます。 そして、「許可」を意味する「allow」を書きます。最後に、ディレクトリ名「sample」をいれます。 まとめると以下のようになります。 $ setfacl -a 1 u:another:full_set::allow sample $ getfacl sample # file: sample # owner: username # group: wheel owner@:rwxp--aARWcCos:-------:allow user:another:rwxpDdaARWcCos:-------:allow group@:r-x---a-R-c--s:-------:allow everyone@:r-x---a-R-c--s:-------:allow ちなみに、full_setの他には、以下のACLセットが使えます。
ACLエントリの変更上記の例では、ACLエントリID=1の人(「another」さん)に、「D」や「d」の権限が付いて、 所有者よりも多くのアクセス権限が付いて気に入らない、と思う方もいるかもしれません。 ACLエントリの権限だけを変更する場合は、一旦、ACLエントリを消して、再度追加する方法が推奨されています。 ACLエントリの削除は、「-Xオプション」に、ACLエントリIDの数字を添えて使います。 $ setfacl -x 1 sample $ getfacl sample/ # file: sample/ # owner: username # group: wheel owner@:rwxp--aARWcCos:-------:allow group@:r-x---a-R-c--s:-------:allow everyone@:r-x---a-R-c--s:-------:allow そして、再びACLエントリを追加します。今度は、full_setのようなACLセットの代わりに、owner@のACL修飾子である「rwxp--aARWcCos」をコピペします。 $ setfacl -a 1 u:another:rwxp--aARWcCos::allow sample $ getfacl sample # file: sample # owner: username # group: wheel owner@:rwxp--aARWcCos:-------:allow user:another:rwxp--aARWcCos:-------:allow group@:r-x---a-R-c--s:-------:allow everyone@:r-x---a-R-c--s:-------:allow
ACLエントリの削除さらに、「everyone」や「group」といったUFSの「モード」との互換性のために用意されたACLエントリを削除することもできます。 たとえば、上記の状態から、everyoneのACLエントリを消すためには、 $ setfacl -x 3 sample $ getfacl sample # file: sample # owner: username # group: wheel owner@:rwxp--aARWcCos:-------:allow user:another:rwxp--aARWcCos:-------:allow group@:r-x---a-R-c--s:-------:allow とします。 ちなみに、ここで、「ls」コマンドを打つと、 $ ls -la total 2 drwxr-xr-x 3 username wheel 3 2月 14 16:15 . drwxr-xr-x 5 username wheel 6 2月 14 13:44 .. drwxr-x---+ 2 username wheel 2 2月 14 16:15 sample となります。ディレクトリエントリの「モード」から、「その他」のrとxが無くなっています。 あと、見慣れない「+」が付いていますが、これは、ファイルの「モード」では表現できないACLが付いていることを意味します。
chmodコマンドが失敗するケースこのとき、ディレクトリが存在するZFSのデータセットの「aclmodeプロパティー」が、「restricted」となっている場合、再度「その他(others)」がアクセスできるようにするため、chmodを使うと、エラーとなります。 つまり、以下のように、 $ chmod 755 sample chmod: sample: Operation not permitted となって、chmodが失敗します。 つまり、ファイルの「モード」では表現できないACLが付いているために失敗します。 ちなみに、「aclmodeプロパティー」がデフォルトの「discard」となっていれば、chmodコマンドは成功しますが、さきほど追加した、「another」さん向けのACLエントリが削除されます。
|