SSD Nodes Learn 🎉 VPS $5.50/月〜
ガイド Matt Connor著者 Matt Connor

Linuxのumaskとは?ファイル権限の決まり方を確認

umaskは作成するファイルとディレクトリのモードから権限ビットを削除します。umaskを表示し、実際に作成してモードを読み取り、rootと一般ユーザーで値が異なる理由を確認します。

Linux で umask が行うこと

umask は Linux 上の各プロセスが持つ数値で、そのプロセスが作成する各ファイルとディレクトリのモードを決定します。プログラムは作成時に、必要な権限の組み合わせをカーネルに要求します。カーネルはマスクで指定された各ビットをクリアし、残った権限を適用します。umask がアクセス権を付与することはありません。作成元のプログラムが要求した権限から、ビットを取り除くだけです。

この値はディストリビューション固有の設定ではありません。使用しているアカウントと、シェルの起動方法によって異なります。同じマシン上で、同じ時点に、標準イメージを使用していても、この 2 つの結果が異なる場合があります。したがって、最初に行うべきことはマニュアルで値を調べることではありません。目の前のマシンで実際の値を確認します。

シェルで umask を表示する

umask
umask -S

1 行目はマスクを 8 進数で表示します。2 行目は、同じマスクを、そのマスクが許可する権限として、chmod が受け付ける記号形式で表示します。両方の行を画面に残してください。以下では、シェルに表示された内容と比較します。

umask はディスク上のプログラムではなく、シェルの組み込みコマンドです。type umask で確認してください。これは重要です。組み込みコマンドはシェルプロセス自体を変更するためです。別のプログラムでは自身のプロセスしか変更できず、終了すると変更も失われます。

ファイルとディレクトリを作成し、モードを読み戻す

cd "$(mktemp -d)"
touch probe.file
mkdir probe.dir
stat -c '%a %A %n' probe.file probe.dir

%a はモードを8進数で表示し、%Als -l が使用する drwxr-xr-x 形式で同じモードを表示します。どちらの行も、先ほど表示したマスクと比較してください。マスクで設定されているビットはすべてモードから欠落します。マスクが行う処理は、そのビットをクリアすることだけだからです。%A 列の読み方がまだ明確でなければ、まず drwxr-xr-x の権限文字列を正しく理解してください。

ファイルとディレクトリのモードは異なりますが、その違いの原因はマスクではありません。touch は owner、group、other に read と write を要求します。mkdir は3者すべてに read、write、execute を要求します。同じマスクが、異なる2つの要求に適用されます。そのため、touch で作成したファイルは、マスクの内容に関係なく実行可能にはなりません。execute ビットが最初から要求されておらず、マスクでビットを追加することはできないためです。

( umask a=rwx; touch open.file; stat -c '%a %A %n' open.file )

この括弧内ではコマンドが subshell で実行されるため、変更はその subshell の終了とともに失われます。マスクは現在、クリア対象を何も指定していません。それでも stat は、ファイルに execute ビットがないことを表示します。その後で umask を再度実行すると元の値に戻ります。これは、この設定がディスク上のどこかに保存されるのではなく、プロセス内に存在し、子プロセスに継承されることを示しています。

クリアされた execute ビットの影響が現れるのは、ディレクトリです。

( umask a=rw; mkdir noexec.dir; cd noexec.dir )

通常のユーザーとして実行すると、cdbash: cd: noexec.dir: Permission denied で失敗します。マスクによって、mkdir が要求した execute ビットがクリアされ、execute ビットのないディレクトリには入れないためです。root はこのチェックを回避するため、この影響が現れるのは通常のアカウントだけです。

root と自分のユーザーで umask が異なる理由

別のアカウントから別の方法で同じ測定を実行し、2 つの出力を並べて確認します。

umask
sudo -i umask

sudo -i は root のログインシェルを起動し、その中で組み込みコマンドを実行します。つまり、別のアカウントが別の起動経路を経由してログインする場合に相当します。標準的な Ubuntu および Debian のサーバーイメージでは、2 行に異なる値が表示されることがあります。どちらの行も正しい値です。それぞれの起動経路で生成された値を示しています。以降では、システムのどの部分がその値を生成したのかを説明します。

イメージ上のどのファイルが値を決めていたか

grep -nE '^(UMASK|USERGROUPS_ENAB)' /etc/login.defs
grep -rn pam_umask /etc/pam.d/
grep -rn umask /etc/profile /etc/profile.d/ /etc/bash.bashrc ~/.profile ~/.bashrc 2>/dev/null || echo 'no umask line in the shell startup files'

最初の grep で何も表示されない場合は、^ アンカーを付けずにもう一度実行します。行がコメントアウトされている可能性があり、コメント行は設定ではなくドキュメントだからです。3 番目の grep が、意外な結果になる箇所です。Debian と Ubuntu では、同梱の /etc/profile は自身でマスクを設定せず、主に PAM を参照します。そのため、設定を担っていると思っていたファイルが、実際には該当しないことがよくあります。grep は一致するものがない場合にゼロ以外の終了ステータスを返します。これが、その行が || echo で終わっている理由です。起動時に読み込まれるファイルのどれにもマスクの指定がないイメージでは、何も表示されない代わりにメッセージが表示されます。そのメッセージ自体が調査結果です。

/etc/login.defs は値を示し、PAM が実際に適用します

/etc/login.defsUMASK 行が、多くのガイドで引用されている値です。カーネルもシェルも、このファイルを読み取りません。このファイルを読み取るのは pam_umask です。これは、セッション作成時に実行される PAM(プラグイン可能認証モジュール)のモジュールです。pam_umask は、最初に見つかった値を使用します。順序は、ユーザーの GECOS フィールドにある umask= エントリ、pam_umask.so 行自体に記述された umask= 引数、/etc/login.defsUMASK です。ディストリビューションによってこのモジュールにはパッチが適用されているため、自分のイメージ上で man pam_umask を実行し、表示された順序を確認してください。

このため、/etc/login.defs が 1 つの値を示していても、警告がどちらからも出ないまま、セッションには別の値が適用されることがあります。grep の結果から、どのケースに該当するかを確認できます。pam_umask.so 行に独自の umask= 引数がある場合は、login.defs の行よりもそちらが優先されます。

USERGROUPS_ENAB と root の例外

id -un
id -gn

この 2 つが同じ名前を出力する場合、そのユーザーはユーザー専用グループを持っています。つまり、アカウント作成時に、そのアカウント名と同じ名前のグループが作成されています。pam_umask には usergroups の動作があり、/etc/login.defsUSERGROUPS_ENAB で制御します。これが有効で、アカウントが root ではなく、プライマリグループ名がユーザー名と一致する場合、モジュールはマスクの所有者用桁をグループ用桁にコピーします。その結果、このセッションでは、そのアカウントが作成するすべてのファイルでグループビットを開いたままにするマスクが設定されます。root はモジュール自体によって除外されます。この除外が、同じサーバー上の 2 つのシェルで異なるマスクが出力される最も一般的な理由です。

この規則の背景には、専用グループのメンバーが 1 人だけであるという前提があります。そのため、グループによる書き込みが可能でも、実質的には所有者だけが書き込めます。ただし、誰かがそのグループに 2 人目のメンバーを追加すると、この前提は崩れます。その時点から、そのアカウントが過去に作成したすべてのファイルを新しいメンバーが書き換えられるようになります。しかも、そのためにファイル上でコマンドを実行する必要はありません。各サービスには 最小権限の専用ユーザーアカウントを割り当て、そのグループが意図的に 1 人だけの状態を保つようにしてください。

ログインシェル、非ログインシェル、非対話型シェル

umask
bash -lc 'umask'
bash -c 'umask'

PAM はセッションの作成時に実行されます。loginコンソール上、sshdsusudo -iです。あるシェルが別のシェルを起動した場合、PAM は実行されません。bash -lはログインシェルであるため、/etc/profile~/.profileを読み込みます。ただし、セッションは作成されていないため、pam_umask は呼び出しません。bash -cはいずれのファイルも読み込まず、起動元プロセスのマスクを継承します。cron ジョブ、git hook、サービスマネージャーが起動したプログラムはいずれもこのケースに該当します。そのため、適用されるマスクは親プロセスの値になります。

このため、「/etc/profile に設定したのに、サービスが依然として誤ったモードでファイルを書き込む」という報告がよくあります。サービスはそのファイルを読み込んでいないためです。

設定をどこに置けば再起動後も維持されるか

ワークロードが実際に起動する場所でマスクを設定します。起動経路ごとに読み込むファイルが異なるためです。

  1. ログインするアカウントの場合: UMASK/etc/login.defs に設定します。pam_umask がマシン上のすべてのセッションに適用します。マシン全体の設定であるため、すべてのアカウントに一括で反映されます。
  2. 1 つのアカウントだけに設定する場合: pam_umask.so 行の umask= 引数もマシン全体に適用されます。そのため、ユーザー単位の値はそのユーザーの GECOS フィールド、またはログインシェル用の ~/.profile、対話シェル用の ~/.bashrc に設定します。
  3. systemd 配下のデーモンの場合: unit の [Service] セクションに UMask= を設定します。unit はサービスマネージャーによって起動されるため、/etc/profile は読み込まれず、pam_umask も実行されません。これらの設定のうち、デーモンに到達するのは unit ファイルだけです。
  4. cron またはフックから起動するスクリプトの場合: スクリプトが何かを作成する前に、1 行目で明示的に umask を設定します。
[Service]
UMask=<the octal mask you chose>

その後、同じ起動経路を新しく開始して確認します。ファイルを編集したシェルから確認してはいけません。現在のシェルはすでに自身のマスクを保持しており、設定ファイルを編集しても実行中のプロセスには反映されないためです。

bash -lc 'umask'
sudo -i umask

chmod を後から実行しても同じ修正にはならない理由

chmod は、すでに存在するファイルを修正します。mask は、まだ存在しないファイルの mode を決めます。ディレクトリに対して chmod -R を実行しても、次にサービスが作成するファイルは再び以前の mode になります。その mode はファイルを作成したプロセスに由来し、ディレクトリの変更による影響を受けないためです。

また、時間差も生じます。ファイルの作成から chmod の実行までの間、ファイルはより広い mode のままディスク上に存在します。そのディレクトリを読み取れるプロセスは、誰でもそのファイルを開けます。秘密鍵やバックアップアーカイブでは、この時間差が取り除こうとしていたリスクになります。

作成時に mode を設定してください。install -m u=rw,go= newfile /etc/app/newfile は明示した mode で出力先を作成し、ディレクトリについては mkdir -m が同じ処理を行います。どちらも指定した mode を使用し、mask を無視します。ssh-keygen は書き込む秘密鍵に mode を設定します。そのため、他のファイルが適切でないマシンでも、そのファイルだけは正しいことがよくあります。

通常、影響を受けるのは SSH です。単純な mkdir で作成した ~/.ssh や、cat >>authorized_keys に追記したファイルは、シェルの mask を使用します。StrictModes が有効な場合、sshd は group-writable なディレクトリ内の鍵ファイルを読み取りません。クライアントには Permission denied (publickey) と表示されますが、サーバー側の /var/log/auth.log には実際の原因が記録されます。

Authentication refused: bad ownership or modes for directory /home/deploy/.ssh

このチェックは意図的なものです。VPS で SSH を強化する方法では、このチェックが機能することが前提になります。新しいサーバーでは、アカウントを作成する前に mask を確認してください。新しい VPS で最初の ten minutesと同様に確認しておけば、それらのアカウントが作成するすべてのファイルの mode を事前に確定できます。

コピーとアーカイブではマスクは無視されます

cp -prsync -a は、ソースファイルに記録されたモードを復元するため、結果に対してマスクは影響しません。tar も、root として、または -p を指定した一般ユーザーとして展開する場合は同じ動作になります。バックアップから復元したファイルは、バックアップを作成した時点のモードを保持します。正しいマスクが無視されていると結論付ける前に、この点を確認してください。復元データでは、マスクは最初から参照されていません。

FAQ

cron ジョブが ssh セッションと異なるモードでファイルを作成するのはなぜですか?

cron ジョブはログインセッションではないため、pam_umask は実行されず、/etc/profile~/.profile も読み込みません。ジョブを開始したプロセスのマスクを継承します。スクリプトが何かを作成する前に、1 行目へ明示的な umask を記述してください。また、ジョブ内部でマスクを 1 回出力し、自分のシェルの値ではなく、そのジョブが実際に持つ値を確認してください。

/etc/login.defs とシェルの出力が異なるのはなぜですか?

/etc/login.defs にある UMASK は、pam_umask にとって最後のフォールバックにすぎません。このモジュールは、まずユーザーの GECOS フィールドにある umask= エントリを使用し、次に /etc/pam.d/pam_umask.so 行にある umask= 引数を使用します。USERGROUPS_ENAB で有効になる usergroups の動作により、root 以外のアカウントで、プライマリグループ名がアカウント名と同じ場合はグループ桁が書き換えられます。grep -rn pam_umask /etc/pam.d/id -un; id -gn を実行すると、これらのどれがアカウントに適用されるかを確認できます。

umask でファイルを実行可能にできますか?

いいえ。マスクでクリアできるのは、作成元のプログラムが要求したビットだけです。touch は実行ビットを要求しないため、どのマスクを指定しても実行可能ファイルにはなりません。使い捨てのディレクトリで ( umask a=rwx; touch f; stat -c '%a %A' f ) を実行して確認してください。実行ビットを付けるには chmod が必要です。または、作成時に実行ビットを要求する install -m のようなプログラムを使用します。

systemd サービスの umask はどこで設定しますか?

unit の [Service] セクションで UMask= を指定します。サービスはログインではなくサービスマネージャーによって起動されるため、シェルの起動ファイルは読み込まれず、pam_umask も実行されません。systemctl daemon-reload を実行して unit を再起動した後、外部から確認してください。サービスにファイルを作成させ、その結果を stat -c '%a %n' で読み取ります。

グループ書き込み可能なデフォルトマスクは安全ですか?

グループのメンバーが正確に 1 人である間は安全です。これは user private group 方式の前提です。そのグループに 2 つ目のアカウントを追加すると、最初のアカウントが作成したすべてのファイルが、その新しいメンバーによって直ちに書き込み可能になります。これらのファイル上でコマンドを実行する必要はありません。id -unid -gn を実行してください。同じ名前が出力されれば、private group を使用しています。アカウント間でグループを共有する場合は、グループの書き込みビットをクリアするマスクを設定してください。その後、ファイルを作成し、stat -c '%a %n' を読み取って変更が反映されたことを確認します。

#umask#permissions#pam#login-defs#linux