シナリオ
深夜2時。設定ファイルが壊れ、デプロイは失敗し、上書きするしかない状況です。rootで実行します:
rm: cannot remove 'config.conf': Operation not permitted
sudo rm -fを試します。同じエラー。chmod 777も試します。これも失敗。所有者を確認すると — rootが所有しています。何も意味をなしません。
ほぼ確実に、これはchattrによって設定されたイミュータブルフラグが原因です。このフラグはPOXISパーミッションより下位のレイヤーに存在し、rootであっても明示的に解除しなければバイパスできない独立した層です。
なぜこうなるのか
Linuxのパーミッションを2層構造として考えてください。おなじみのrwxrwxrwxビットは外側の層 — 誰もが知っているものです。その下に拡張属性システムがあり、その属性の一つが+iです。ファイルにこれが設定されると:
- 誰もそのファイルを変更、削除、リネーム、またはハードリンクの作成ができない
- rootでさえも不可能
-fオプションを使っても不可能
ファイルがイミュータブルになる原因は?通常以下のいずれかです:
- システム管理者が意図的にロックした —
/etc/resolv.confや/etc/hostsでよく見られる - プロビジョニングツール(Ansible、Chef、Puppet)がハードニングの一環として設定した
- インストーラーやパッケージスクリプトが追加した
- 設定ファイルの誤上書き防止のために誰かが設定した
- 稀なケース:ルートキットが自身を守るために設定 — 頭の片隅に置いておく価値あり
診断:イミュータブルフラグを確認する
ファイルに対してlsattrを実行します:
lsattr config.conf
イミュータブルなファイルは属性文字列にiが表示されます:
----i---------e-- config.conf
このiが原因です。ディレクトリ全体を確認するには、再帰的にスキャンします:
lsattr -R /etc/nginx/
システムにlsattrがない場合はインストールします:
# Debian/Ubuntu
apt install e2fsprogs
# RHEL/CentOS
yum install e2fsprogs
クイックフィックス:イミュータブルフラグを解除する
コマンド一つで解除できます:
# 単一ファイルのイミュータブルフラグを解除
sudo chattr -i config.conf
# 削除する
rm config.conf
削除ではなく編集したい場合も最初のステップは同じです:
sudo chattr -i config.conf
nano config.conf
ディレクトリツリー全体を対象にする場合:
sudo chattr -iR /path/to/directory/
修正を確認する
# フラグが解除されたことを確認
lsattr config.conf
# 属性に 'i' が表示されないはず:
# ---------------e-- config.conf
# 削除が成功するはず
rm config.conf
echo $? # 0 が表示されるはず
その他の原因(chattr が問題でない場合)
それでもエラーが出るがlsattrにイミュータブルフラグが表示されない?他に考えられる原因:
SELinux
RHEL/CentOS/Fedoraでは、SELinuxが他のすべての上に独自のアクセスルールを適用します — rootも例外ではありません:
# SELinuxがブロックしているか確認
audit2why -a | grep denied
# ファイルのSELinuxコンテキストを確認
ls -Z config.conf
# 一時的に許可モードに切り替え(テスト目的のみ)
sudo setenforce 0
rm config.conf
sudo setenforce 1
マウントオプション(読み取り専用ファイルシステム)
# マウントフラグを確認
mount | grep "$(df config.conf | tail -1 | awk '{print $1}')"
# オプションに 'ro' がないか確認
AppArmor(Ubuntu)
# AppArmorの拒否を確認
dmesg | grep -i apparmor | tail -20
aa-status
NFSまたはリモートファイルシステム
NFS上のファイルは動作が異なります。root_squashオプションはサーバー側でrootを非特権ユーザーにマッピングします — ローカルではrootでも、リモートでは実質的に一般ユーザー扱いになります。NFSサーバーの/etc/exportsを確認してください。rootアクセスを復元するにはno_root_squashが必要です。
恒久的な対処:フラグを残すべきか判断する
フラグを解除して先に進む前に、30秒だけなぜそこにあったのかを考えてください。本番システムのイミュータブルフラグは通常、過去のインシデント、コンプライアンス要件、または次回実行時に再設定する自動化ツールなど、特定の理由で設定されています。
誰が設定したかを調べます:
# AnsibleプレイブックでのchattrのCallを検索
grep -r "chattr" /etc/ansible/
# シェル履歴を確認(利用可能な場合)
grep chattr ~/.bash_history
特に管理された設定ファイルには注意してください。/etc/resolv.confがNetworkManagerやdhclientによるDNS設定の上書きを防ぐためにイミュータブルにされていた場合、フラグを解除すると次回再起動時に上書きされます。根本的な解決策はこれらのサービスがファイルを変更しないようにすることです:
# NetworkManagerがresolv.confを上書きしないよう設定
echo -e "[main]\ndns=none" | sudo tee /etc/NetworkManager/conf.d/nodns.conf
sudo systemctl restart NetworkManager
クイックリファレンス
# 属性を表示
lsattr filename
lsattr -R /directory/
# イミュータブルを設定
sudo chattr +i filename
# イミュータブルを解除
sudo chattr -i filename
# その他の便利なフラグ:
# +a 追記専用(書き込みは可能だが削除・上書きは不可)
# +u 削除不可(データを復元のために保持)
sudo chattr -a filename # 追記専用を解除
ヒント
パーミッションのデバッグ中にファイルのビットが何を意味するのかわからなくなったとき、ToolCraftのUnix Permissions Calculatorはchmod値を素早くデコードするのに便利です — イミュータブルフラグを解除した後にファイルのパーミッションを復元する前に、正しい値を確認するのに役立ちます。

