「rootなら何でもできる」という誤解。
こんにちは!「LINUX工房」管理人の「リナックス先生」です。
前回は、スクリプト機能を使ってサービスの再起動や通知を自動化する方法を学びました。
さて、logrotateの設定も完璧、スクリプトも書いた。それなのに、いざ動かしてみると「Permission denied(許可がありません)」という無慈悲なエラーメールが届くことがあります。
「えっ? logrotateってスーパーユーザー(root)で動いてるんじゃないの? rootに拒否権なんてあるの?」
そう思ったあなたは、Linuxの権限管理の奥深さにまだ気づいていないかもしれません。
先生、助けてください!
自分で作ったJavaアプリのログをローテートさせようとしたら、エラーが出て止まっちゃいました。
しかも、エラーが出た後、アプリがログファイルに書き込めなくなって落ちちゃったんです!
所有者が勝手に root に変わってるし…どうしてこんな意地悪するんですか?
それは意地悪じゃなくて、logrotateの仕様通りの動きよ。
logrotateはデフォルトでは root 権限で動くから、新しく作ったファイルの所有者も root になってしまうの。
一般ユーザーで動いているアプリからすれば、いきなり書き込み禁止にされたようなものね。
今回は、この「権限の衝突」を解決するための su ディレクティブと create の正しい使い方をマスターしましょう!
本記事では、AlmaLinux 9 をベースに、logrotateにおけるユーザー権限の取り扱い、su ディレクティブによる実行ユーザーの切り替え、そしてセキュリティ機能である「親ディレクトリの権限チェック」の回避方法までを徹底解説します。
🔄 logrotate完全攻略講座(バックナンバー)
現在地:【第6回】権限トラブルを回避する!ユーザー指定とACL、出力先ディレクトリの管理
- 【第1回】サーバーの「時限爆弾」を解除せよ!ログローテーションの基礎と仕組み完全図解
- 【第2回】設定ファイルの魔術書!ローテーション周期・サイズ・保存期間の完全制御
- 【第3回】「ログが消えた!?」を防ぐ。copytruncateとcreateの決定的な違いとiノードの秘密
- 【第4回】ディスク容量を極限まで節約!圧縮設定と日付付与のテクニック
- 【第5回】再起動を自動化せよ!postrotateスクリプトによるプロセス制御
- 【第6回】権限トラブルを回避する!ユーザー指定とACL、出力先ディレクトリの管理
- 【第7回】動かない時の処方箋。デバッグモード活用とSELinux/ステータスファイルの罠
- 【第8回】最強のバックアップ構築。S3への自動転送と一元管理への応用
第1章:なぜ権限エラーが起きるのか?
logrotateは cron から起動されるため、基本的にはシステム最高権限である root ユーザーとして実行されます。
これが、一般ユーザー権限で動作するアプリケーション(Node.js, Python, Javaなど)と衝突する原因になります。
悲劇のシナリオ
- 通常時:
アプリ(ユーザー:webapp)がapp.log(所有者:webapp)に書き込んでいる。平和。 - ローテーション発生:
logrotate(ユーザー:root)が起動。 - リネーム:
app.logをapp.log.1に変更。所有者は元のまま(webapp)。 - 新規作成 (create):
logrotateが新しいapp.logを作成。
作成者がrootなので、新しいファイルの所有者はrootになる! - アプリ書き込み不能:
アプリ(webapp)は、root所有になった新しいapp.logに書き込む権限がなく、エラーで停止する。
この問題を解決するには、「新しいファイルを誰のものにするか」をlogrotateに明示的に指示する必要があります。
第2章:create ディレクティブの正しい使い方
最も基本的な解決策は、create ディレクティブを使って、新しく作成されるログファイルの権限と所有者を指定することです。
構文
create [パーミッション] [所有ユーザー] [所有グループ]
設定例
Webアプリケーションのユーザーが webapp、グループが webapp の場合。
/var/log/webapp/*.log {
daily
rotate 7
missingok
notifempty
compress
# ここが重要!
create 644 webapp webapp
}
これにより、logrotateはファイル作成後に自動的に chown webapp:webapp を実行してくれるため、アプリは引き続きログに書き込むことができます。
💡 補足:copytruncate の場合
copytruncate モードを使う場合、元のファイル自体は消えずに中身だけ空にされるため、iノードも所有者も変わりません。
したがって、理論上は権限問題は起きにくいですが、念のため create を指定しておくのが安全です(ファイルが消失していた場合の再作成時などに有効)。
第3章:実行ユーザーそのものを切り替える「su」
create だけでは解決できない問題があります。
それは、「ログディレクトリ自体の権限」です。
例えば、ログディレクトリ /home/webapp/logs/ のパーミッションが 700 (rwx------) で、所有者が webapp だったとします。
rootユーザーは最強なので読み書きできますが、NFSマウントされたディレクトリや、特殊な環境ではrootでもアクセスが制限されることがあります。
また、セキュリティの観点から「そもそもrootで作業させたくない」という場合もあります。
そんな時に使うのが su ディレクティブです。
su ディレクティブの役割
logrotateの実行プロセスそのものを、指定したユーザー/グループに切り替えて(SetUIDして)処理を行います。
su [ユーザー] [グループ]
設定例
/home/webapp/logs/*.log {
# webappユーザーになりすまして実行
su webapp webapp
daily
rotate 7
create 644 webapp webapp
}
これを指定すると、ファイルのリネーム、圧縮、削除などのすべての操作が webapp ユーザーの権限で行われます。
当然、create で指定するユーザーも webapp である必要があります。
⚠️ 注意点:postrotate スクリプトの実行権限
su を指定している場合、postrotate 内のスクリプトもそのユーザー(webapp)権限で実行されます。
つまり、スクリプト内で systemctl reload httpd のような root権限が必要なコマンドを実行すると失敗します。
この場合、sudo を使うか、su を使わずに運用設計を見直す必要があります。
第4章:親ディレクトリの権限チェック機能
su ディレクティブを使った時によく遭遇するエラーがあります。
error: skipping "/var/log/myapp/app.log" because parent directory has insecure permissions (It's world writable or writable by group which is not "root") Set "su" directive in config file to tell logrotate which user/group should be used for rotation.
これは logrotate のセキュリティ機能によるものです。
「ログファイルが置かれているディレクトリ(親ディレクトリ)が、誰でも書き込める状態(777など)になっているのは危険だ」と判断し、処理を拒否しているのです。
なぜ危険なのか?
もしディレクトリが誰でも書き込める状態だと、悪意あるユーザーがローテーションの瞬間にログファイルをシンボリックリンクに置き換えることで、システムファイル(/etc/passwdなど)を上書きさせたり、削除させたりする攻撃(Symlink Attack)が可能になるからです。
解決策
- ディレクトリの権限を絞る(推奨):
ログディレクトリのパーミッションを755や750にし、所有者以外が書き込めないようにします。
chmod 755 /var/log/myapp - su を使う:
エラーメッセージにもある通り、su [ユーザー] [グループ]を指定することで、「このユーザーの責任でやるならOK」と許可される場合があります。
第5章:高度な権限管理「ACL」への対応
現場では、「アプリ(Aさん)が書き込みたいし、ログ収集エージェント(Bさん)も読み込みたい」という複雑な要件が出ることがあります。
標準のパーミッション(所有者・グループ・その他)だけでは対応しきれません。
そんな時に使うのが ACL (Access Control List) です。setfacl コマンドで、特定のユーザーに追加の権限を与えることができます。
logrotateとACLの問題点
logrotateが create モードで新しいファイルを作るとき、デフォルトでは ACL設定は引き継がれません。
古いログにはACLが付いていても、新しいログには付いていないため、翌日からログ収集エージェントが「Permission denied」で読めなくなるトラブルが発生します。
解決策:postrotate で ACL を再設定する
残念ながら、logrotateには「ACLを引き継ぐ」というオプションはありません。postrotate スクリプトを使って、毎回ACLを設定し直すのが定石です。
/var/log/myapp/*.log {
daily
create 640 webapp webapp
postrotate
# 新しいログファイルに、fluentdユーザーの読み込み権限(ACL)を付与
/usr/bin/setfacl -m u:fluentd:r /var/log/myapp/app.log
# アプリのリロード
/bin/systemctl reload myapp
endscript
}
これで、ローテーション後も常に正しいアクセス権限が維持されます。
第6章:権限エラーのトラブルシューティング
権限周りでハマった時の確認フローです。
Check 1: ログファイルの所有者
ls -l /var/log/myapp/app.log
これが root:root になっていたら、create ディレクティブの設定漏れです。
Check 2: 親ディレクトリの権限
ls -ld /var/log/myapp/
logrotateを実行するユーザー(通常はroot、su指定時はそのユーザー)が、このディレクトリに対して「書き込み権限(w)」と「実行権限(x)」を持っている必要があります。
ファイルのリネームや作成は、ディレクトリへの書き込み権限が必要だからです。
Check 3: SELinuxのコンテキスト
権限は合っているのに「Permission denied」が出る場合、9割はSELinuxです。ls -Z でコンテキストを確認し、必要なら var_log_t などを付与してください(第7回で詳しく解説します)。
まとめ:権限管理は「誰が書くか」を意識する
お疲れ様でした!
logrotateの設定の中でも、最も躓きやすい権限周りについて解説しました。
今回の重要ポイント:
- logrotateはデフォルトでroot権限で動く。
- 一般ユーザーのアプリには
create [ユーザー] [グループ]が必須。 suを使うと実行ユーザーごと切り替えられるが、スクリプトの権限に注意。- ACLを使う場合は、
postrotateで再設定が必要。
ここまで設定しても、まだ動かないことがあります。
「設定は完璧なはずなのに、なぜか回らない」「エラーログにも何も出ていない」…
そんな時に役立つのが、logrotateの「デバッグ機能」と、隠れた支配者「ステータスファイル」の知識です。
次回、第7回は「動かない時の処方箋。デバッグモード活用とSELinux/ステータスファイルの罠」です。-d オプションの出力結果の読み解き方や、logrotateが過去の実行履歴をどう管理しているか、そしてSELinuxの詳細なトラブルシュートまで、プロのデバッグ術を伝授します。
解決できないエラーなどありません。お楽しみに!
▼ 安全な権限管理を実践する ▼
ユーザー権限を検証
「VPS」で自分専用環境
Linuxセキュリティを年収に
「ITエンジニア転職」

コメント