ログは追記できるが再作成できない:ディレクトリのACLを確認する
既存ファイルへの追記にはディレクトリ内の新しい名前は不要だが、作成には必要だ。何かを広げる前に、アクセスACLと継承された既定値を比較する。
成長し続けるログは、何かがそれを再作成した瞬間に成長を止め、エラーは許可が拒否されたと告げる。誘惑される結論は、ログファイル自体にもっと権限が必要だというものだが、そのファイルは同じアカウントですでに書き込み可能かもしれない。既存の名前への追記と新しい名前の作成は別の検査であり、ディレクトリを参照するのは二つ目だけだ。
追記と作成は別の検査
既存ファイルを追記用に開くには、そのファイルへの書き込みアクセスと、そのパス上の各ディレクトリへの検索アクセスが必要だ。ファイルの作成には、それを含むディレクトリへの書き込みと検索が必要である。なぜなら操作がそこに名前を加えるからだ。名前変更によるファイルの置き換えは、両方のディレクトリとそのスティッキービットの規則にも触れる。
| Operation | What must permit it | Typical failure message |
|---|---|---|
| Append to an existing log | File write access, path traversal | Permission denied on the file |
| Create a missing log | Directory write and search access | Permission denied on the path |
| Rename a replacement into place | Both directories, plus sticky restrictions | Permission denied or operation not permitted |
すでに開いているディスクリプタは第四のケースを加える。プロセスは特権を落とす前に開いた書き込みハンドルを保持したまま、後の身元で同じパスを開き直すのに失敗することがある。追記の成功と作成の失敗は、同じプロセスについて、同じ瞬間に両方とも真でありうる。
既定ACLは継承するもので、付与はしない
既定の接頭辞で始まるエントリは、新しいオブジェクトがディレクトリから何を継承するかを記述する。それはディレクトリ自体に何も付与せず、すでに存在するファイルのACLを修復もしない。
namei -l /var/log/openvpn/server.log
getfacl -p /var/log/openvpn
getfacl -p /var/log/openvpn/server.log
アクセスエントリは既定のものとは別に読み、マスクも読む。完全な権利を並べる名前付きエントリでもマスクによって制限されうる。だからこそ、実効コメントは先頭行の文字より重要だ。
設定のパスではなく解決済みのパスを使う。シンボリックリンク、マウントポイント、回転したディレクトリは、与えた権限が決して届かない場所に実ファイルを置きうる。まず名前ツールでパスをたどり、次に各階層を問題のアカウントと比較する。最上位ディレクトリを推測することが、修正が一段高すぎる位置に着地する原因だ。
その瞬間に誰が書き込むのかを特定する
何かを変える前に、サービスユニット、そのドロップイン、デーモン自身のアカウント設定を確認する。追記するプロセスと再作成するプロセスは別かもしれない。ローテーションヘルパー、ステータス書き込み、Webリーダーが同じ身元を共有することはまれだ。
rootシェルからのテスト実行は制限されたサービスを再現しない、そしてサービスが失敗し続ける間もそれは成功する。失敗した操作を同じユニット、同じアカウント、同じサンドボックス設定で再現する。できないなら、一時的なシェルでユニットを起動し、報告される身元を確認する。それ以外はサービスではなく端末を測っている。
作成が本当に必要なら、書き込み側に専用のログディレクトリへのアクセスを与え、読み取り側のアクセスは別に保つ。ログ呼び出し一つを満たすために共有アカウントやアプリケーション全体のツリーを書き込み可能にするのは、小さな問題を大きな問題と引き換えることだ。
再発させずにローテーションする
ファイルを再作成する者が次のサイクルの所有者とモードを決めるので、修正はローテーション設定と調整する。別のアカウントで、あるいは新しいACLで作られた代替ファイルは、修正が成功した後で障害を呼び戻す。
モードとグループは作成時に設定し、後からではなく、次の追記ではなく次のローテーションを検証する。追記はすでに通ったテストを繰り返すだけだ。ローテーションツールが作成モードの設定を提供するなら、作成後のchmodの代わりにそれを使う。作成とchmodの間の隙間こそ、次の書き込みが失敗しうる瞬間だ。
切り詰めがそれでも失敗するときは、権限を足すのをやめる
書き込めるファイルの切り詰めの失敗は、ディレクトリの権限では説明できず、権限を足しても助けにならない。代わりに属性と制限を見る。追記専用属性は追記モードでの書き込みだけを許し、読み取り専用のマウントやサービスのサンドボックスはACLが許す操作を拒否しうる。
ユニットのファイルシステム制限とそのパスのマウントオプションを確認し、失敗した正確な操作を再現する。決して参照されなかった権限を広げても、どの制限が本当だったかを隠すだけだ。使い捨てのユニットで一度に一つの制限を外し、恒久的な変更の前に元に戻す。