sysadminを始めたばかりの頃、なかなか頭を悩ませる状況に直面したことがある。deployというユーザーにアプリケーションのログを読ませたいのだが、そのファイルはwww-dataユーザーの所有物で、セキュリティ上の理由からdeployをwww-dataグループに追加したくなかった。chmod 644で解決? いや、それだと読んではいけない他のユーザーまで読えてしまう。まさにこういうとき、chmod/chownでは手の施しようがない問題をACL(Access Control List)が解決してくれる。
うちの会社にはまだCentOS 7で動いているサーバーが数台あり、AlmaLinuxへの移行は自分が担当した課題だ。移行のたびにACLは必ず確認し直す必要がある。なぜなら、通常のrsyncはACLを保持せず、移行後に原因の特定が難しいpermissionエラーを引き起こしやすいからだ。
ACLとは何か、なぜ必要か?
Linuxの伝統的なパーミッションには3つの対象しかない:owner、group、そしてothersだ。シンプルではあるが、企業環境でユーザー数が増えてくると柔軟性に欠ける。
ACLを使えば、ファイルの現在のownerやgroupに関係なく、任意のユーザーやグループに個別のパーミッションを設定できる。システムはPOSIXパーミッションを通常通り処理し、ACLはその上に追加された拡張レイヤーに過ぎない。
ACLが必要になる実際のシナリオをいくつか挙げる:
- ディレクトリ
/var/www/htmlはフロントエンドチームに読み書きさせたいが、wheelグループ全体には与えたくない - ログファイルはmonitoringエージェントに読ませたいが、他のユーザーには公開したくない
- 共有プロジェクトディレクトリで、dev、QA、PMそれぞれに異なるパーミッションを設定したい
押さえておくべき核心概念
主要な2つのツール
getfacl— ファイルまたはディレクトリの現在のACLを表示するsetfacl— ACLを設定する
Maskとは何か?
Maskは、named user、named group、またはowning groupが持てるパーミッションの上限を定めるものだ。ownerとothersには影響しない。ACLが設定されているファイルに対してchmodを実行すると、ACLが削除されるのではなくmaskが更新される。これは初めて使う際によく誤解されるポイントだ。
実践:CentOS Stream 9でACLを段階的に管理する
ステップ1:ACLのインストールと対応確認
CentOS Stream 9では、XFS(デフォルトのファイルシステム)はACLがデフォルトで有効になっている。aclパッケージをインストールするだけでよい:
sudo dnf install acl -y
# インストールの確認
getfacl --version
ファイルシステムがACLサポート付きでマウントされていることを確認したい場合:
mount | grep -E "^/dev"
# XFSはデフォルトで有効なため、通常'acl'は表示されない
ステップ2:ファイルの現在のACLを確認する
# テスト環境の作成
mkdir -p /tmp/acl-demo
touch /tmp/acl-demo/testfile.txt
# ACLの確認
getfacl /tmp/acl-demo/testfile.txt
拡張ACLがない場合の出力:
# file: tmp/acl-demo/testfile.txt
# owner: root
# group: root
user::rw-
group::r--
other::r--
ステップ3:特定のユーザーとグループにACLを追加する
# 構文: setfacl -m u:<username>:<permissions> <file>
sudo setfacl -m u:alice:rw /tmp/acl-demo/testfile.txt
# グループへの追加
sudo setfacl -m g:developers:r /tmp/acl-demo/testfile.txt
# 結果の確認
getfacl /tmp/acl-demo/testfile.txt
ACL追加後の出力:
# file: tmp/acl-demo/testfile.txt
# owner: root
# group: root
user::rw-
user:alice:rw-
group::r--
group:developers:r--
mask::rw-
other::r--
ls -laを実行すると+記号が表示される:-rw-rw-r--+ — これはgetfaclを実行しなくてもファイルにACLが設定されていると素早く識別する方法だ。
ステップ4:Default ACL — 最も重要な機能
Default ACLは実務で最もよく使う機能だ:ディレクトリ内に新しく作成されたファイルが自動的にACLを継承するため、毎回設定し直す必要がない。
mkdir /tmp/acl-demo/shared
# -dフラグ = default ACL
sudo setfacl -d -m u:alice:rwx /tmp/acl-demo/shared
sudo setfacl -d -m g:developers:rx /tmp/acl-demo/shared
# 設定の確認
getfacl /tmp/acl-demo/shared
出力内のdefault:セクションは、その中に新しく作成されたファイルやサブディレクトリに自動的に適用される。
ステップ5:ACLを再帰的に適用する
# -R = 再帰的
sudo setfacl -R -m u:alice:rx /var/www/html
# 再帰 + defaultを組み合わせることで、既存のディレクトリツリーと新規ファイルの両方をカバーできる
sudo setfacl -R -d -m u:alice:rx /var/www/html
ステップ6:ACLを削除する
# 特定ユーザーのACLを削除する
sudo setfacl -x u:alice /tmp/acl-demo/testfile.txt
# 拡張ACLをすべて削除する(基本的なPOSIXのみ残す)
sudo setfacl -b /tmp/acl-demo/testfile.txt
# ディレクトリのdefault ACLを削除する
sudo setfacl -k /tmp/acl-demo/shared
実践例:複数開発チームの環境
ディレクトリ/opt/webappに対して以下のようなパーミッション要件があるとする:
- ユーザー
deploy:全体の読み/書き/実行 - グループ
dev:コードの読み/書き、任意スクリプトの実行は不可 - グループ
qa:読み取りのみ - ユーザー
monitor:logsディレクトリの読み取りのみ
# ルートディレクトリのパーミッション設定
sudo setfacl -R -m u:deploy:rwx /opt/webapp
sudo setfacl -R -m g:dev:rw /opt/webapp
sudo setfacl -R -m g:qa:r /opt/webapp
# logsディレクトリの個別パーミッション設定
sudo setfacl -R -m u:monitor:rx /opt/webapp/logs
# 新規ファイルが継承するようdefault ACLを設定
sudo setfacl -d -m u:deploy:rwx /opt/webapp
sudo setfacl -d -m g:dev:rw /opt/webapp
sudo setfacl -d -m g:qa:r /opt/webapp
# 全体の確認
getfacl /opt/webapp
ls -la /opt/webapp
サーバー移行時のACLバックアップとリストア
これはCentOS 7からAlmaLinuxへの移行時に学んだ教訓だ。rsync完了後、ACLが失われたためいくつかのサービスが動かなくなった。それ以来、移行前には必ずACLをバックアップするようにしている:
# /var/wwwのACLをすべてバックアップする
getfacl -R /var/www > /backup/www-acl-backup.txt
# バックアップからリストアする
setfacl --restore=/backup/www-acl-backup.txt
# -Aフラグ付きrsyncでACLを保持する
rsync -aAX /source/ /destination/
まとめ
ACLはchmod/chownを置き換えるものではなく、従来のPOSIXパーミッションでは柔軟性が足りない場合に制御レイヤーを追加するものだ。ACLを使うべき状況:
- ownershipを変更せずに、同じファイルに対して複数のユーザー/グループへ異なるパーミッションを設定したい場合
- ディレクトリ内に新規作成されたファイルが、default ACLを通じて自動的にパーミッションを継承してほしい場合
- 複数チームが重複したパーミッション要件を持つ環境
CentOS Stream 9やAlmaLinuxのサーバーを管理しているなら、getfaclコマンドでシステム上に設定されているACLがないか確認してみてほしい。前の担当者がドキュメントを残さずにACLを設定していることがあり、それが原因で説明のつかないpermissionエラーが発生している場合もある。

