POSIX ACLでのフル権限化の再構築
そもそも、この記事は何なのか。簡潔に言うとLinux、WSL2でのDocker環境でのファイルや、フォルダの所有者がコンテナとホストで同一になる事から来る有名な権限問題について、コンテナ側にホスト側の作業ユーザと同じUID,GIDのユーザを作って、それでログインする方法が一番、きれいな方法なのは、わかってるけれども、そもそも、この権限問題が発生しないMacユーザがチーム内にいて、rootでログインするだけのDockerfileが連携されたときに、Linux、WSL2ユーザとして最も、楽な解決方法の裏技を示しているのが当記事である。記事内にあるシェルスクリプトをコピペしてホームディレクトリにおいて、それをローカルのgitのルート(プロジェクトフォルダ)のパスを指定して実行するだけを1回やるだけでOK状態となる。お手軽で非常に強力な裏技です。
devcontainersも使わず、直でdocker compseの環境などで、
rootユーザでログインすることが前提なだけのDockerfileの時
Linuxや、WSL2ユーザの場合、バインドマウントしてるファイルや、フォルダについて、
コンテナ側で作業時、ファイルやフォルダがroot所有になってしまい
ホスト側で、一般ユーザで作業時に、それらが、パーミッションエラーになってしまう問題
gitでブランチの切り替えや、プルなどで、それらを更新したり、削除が発生するものを
しようとしたときに、パーミッションエラーで止まってしまう
などの問題がある
ちゃんと、DockerfileでUID,GIDが1000:1000のユーザをコンテナに作成し
そのユーザでパスワードなしでsudoが使えるようにする(sudersの登録して)
などして、コンテナには1000:1000でログインする(devcontainerならそういう環境に自動でできる)
などのするのが、きれいなやり方だとわかってます。
しかし、チームメンバーにMacユーザがいた場合、Docker for Macは、virtiofsなどのファイル共有で
バインドマウントしており、コンテナ側がroot所有でも、ホスト側は一般ユーザ所有に見えて
このパーミッションエラーがおきないため、rootユーザでログインすることが前提なだけのDockerfile
がチーム内で連携されがちになる
このとき、Linuxや、WSL2ユーザは、下記に示した
aclfull.shを、作業ユーザのホームディレクトリに作成し
/example/path/localGitDirがローカルのgitのルートや、プロジェクトフォルダだったとき
~/aclfull.sh /example/path/localGitDir
を打ち込むだけで
作業ユーザは、/example/path/localGitDir配下、末端までフル権限で作業ができて
たとえ、root所有のファイルや、フォルダであっても
問答無用で更新、削除が行えてしまえます
なぜなら、一般的なファイルや、フォルダのパーミッションより
ACLの設定のほうが優先的に評価されるからです。
このPOSIX ACLは、20年以上前からLinux(他のUnixでも)使える
枯れた技術なので信頼性は高いです。
そして、/example/path/localGitDir配下、末端まで、
既存のファイルや、フォルダだけでなく、新しく追加されたファイルや、フォルダにも適用されます
そのため、
~/aclfull.sh /example/path/localGitDir
を、1回実行しておくだけで、
補足)
ただし、配下でchmodコマンドを使った場合、その位置より末端まで
POSIX ACLが効かなくなってしまうため、その場合は、
再度、ローカルのgitのルートの/example/path/localGitDirを指定して
~/aclfull.sh /example/path/localGitDir
の実行のしなおしをすれば、また完全に末端まで適用されますので
その実行のし直しをしておくのがオススメです。
rootユーザでログインすることが前提なだけのDockerfile
の状況でも、簡単に所有者違いのパーミッションエラーの問題を起こさず
開発作業が行えるようにできる
この簡単に一発解決できる強力な【裏技】について、当記事では書いております
前提として「POSIX ACL」がインストールされてる必要あり
which getfacl
を打ち込んで、/usr/bin/getfacl
などのパスが表示されたら「POSIX ACL」がインストールされてます
$ which getfacl
/usr/bin/getfacl
$
上記で何も表示されていなければ、「POSIX ACL」がインストールされてません
その場合は、下記のコマンドでインストールしてください
sudo apt-get update
sudo apt-get install acl
インストール後に、
再度、which getfacl
を打ち込んで、/usr/bin/getfacl
などのパスが表示されることを確認してください
はじめに
諸事情があり
https://zenn.dev/tazzae999jp/articles/07bed12c3ae6c0#posix-acl
でのやり方では不十分な場合があった
デフォルトACL(Default ACL)の設定が残ってるデータを
持ってきた場合の既存データで、うまく、効かないケースがあり
その影響で、コンテナでroot所有となったファイルの更新ができないレアケースがあった
その可能性も完全に消し去る方向性で考えた時に
複雑になってしまったため
★ ログインユーザのホームディレクトに直下に ★
★ aclfull.sh という名前のシェルスクリプトファイルを作成し ★
★ 中身は、下記の内容を、そのままコピペして ★
~/aclfull.sh /example/path/localGitDir
の形で実行
補足)
/example/path/localGitDir
は、
自分の「gitリポジトリなどソースコードを管理しているルート領域」などを指定
するだけで、一発OKとする形にしようと思った
このサイトからのコピペでいつでも簡単にシェルスクリプトが作成できる
状況にしとけば、それでよしということにした。
getfacl /example/path/localGitDir
で、軽く確認だけすればよい。
aclfull.sh の中身
下記をコピペして作る
#!/usr/bin/env bash
# -----------------------------------------------------------------------------
# aclfull.sh
# 目的:
# /path/under/target 配下の「既存の全ファイル・全ディレクトリ」と
# 「これから新規に作られるもの」の両方に対して、
# 現在ログイン中のユーザーとその主グループに “フル権限(rwx)” を付与する。
#
# ポイント(超重要・初心者向けの要点):
# - ACLには2種類あります:
# 1) アクセスACL(Access ACL) … 既存の実体に“今すぐ”効く
# 2) デフォルトACL(Default ACL)… そのディレクトリ「内で新規に作られるもの」に効くテンプレ
# - よくある誤解:「デフォルトACLを付ければ既存にも効く」→ **効きません**。
# 既存には“アクセスACL”を **再帰** で付ける必要があります。
# - “mask”(ACLマスク)は「ACLの上限」。maskが狭いと effective(実効権限)が落ちます。
# だから **u:…:rwx を付けるだけでなく m::rwx(マスク) も必ず上げる** 必要があります。
#
# このスクリプトがやること(順序は厳守):
# 0) 引数チェック、コマンド存在チェック、安全確認
# 1) 対象ディレクトリの **デフォルトACLの残骸を全消去**(-k)+ ルートのACL一旦クリア(-b)
# 2) あなたが普段やっている「デフォルトACLの付与」を再帰で設定(d:u/d:g と m::rwx)
# → 「これから新規に作られるもの」にフル権限が付く土台を作る
# 3) “既存の全ファイル/ディレクトリ”に対して、アクセスACLで **u/g/m をrwxにして再帰付与**
# → 今あるものに“即時に”フル権限が効く状態にする
# 4) “既存の全ディレクトリ”に対して、**defaultの m::rwx を明示**(新規作成物のmaskも保証)
#
# これにより、「既存も新規も、ユーザー:グループ にフル権限」が 100% 確実になります。
# ※ 所有者 chown / パーミッション chmod / ファイル削除 は一切しません(要求厳守)。
#
# 使い方:
# 1) このファイルを ~/aclfull.sh として保存
# 2) 実行権限を付与: chmod +x ~/aclfull.sh
# 3) 実行例: ~/aclfull.sh /example/path/localGitDir
# (/example/path/localGitDir が対象ルート。配下“末端まで”処理します)
#
# 前提:
# - Linux(WSL2含む)で setfacl / getfacl / find が使えること
# - 対象にACLを設定できるファイルシステムを使っていること(ext4等)
# - 一部の操作は ACL の変更に sudo が必要です
# -----------------------------------------------------------------------------
set -euo pipefail
# ---- color & die (赤字でエラー、必ず色を元に戻す) ---------------------------
RED=$'\e[31m'; BOLD=$'\e[1m'; NC=$'\e[0m'
die() { printf '%s%sERROR:%s %s\n' "$BOLD" "$RED" "$NC" "${1:-failed}"; exit 1; }
# ===== 0) 引数と環境チェック ==================================================
if [ $# -ne 1 ]; then
die "Usage: $0 <target_dir>"
fi
TARGET="$1"
if [ ! -d "$TARGET" ]; then
die "Error: not a directory: $TARGET"
fi
# 必要コマンド確認(存在しないときは明示)
for cmd in setfacl getfacl find id whoami; do
command -v "$cmd" >/dev/null 2>&1 || die "Error: '$cmd' not found in PATH"
done
# 現在のユーザー名と主グループ名を取得(要求どおり whoami / id -gn を使用)
USER_NAME="$(whoami)"
GROUP_NAME="$(id -gn)"
echo "Target: $TARGET"
echo "User : $USER_NAME"
echo "Group : $GROUP_NAME"
echo
# ===== 1) 既存の default ACL を全削除し、ルートのACLも一旦リセット ==========
# - setfacl -k : そのディレクトリの“default ACL”だけを削除(アクセスACLは保持)
# → 配下の全ディレクトリに対して実施し、古いテンプレが新規作成物に紛れないようにする
echo "[1/5] Clear ONLY default ACLs under target (avoid stale defaults)"
sudo find "$TARGET" -type d -exec setfacl -k {} + \
|| die "[1/5] setfacl -k failed on subdirs"
# - setfacl -b : 直指定のパスの ACL(アクセス/デフォルト両方)を一旦クリア
# → ルート直下の余計なACLを初期化(あなたの運用手順に合わせるため)
echo "[1b/5] Clear all ACL on the top directory (reset root ACL of target)"
sudo setfacl -b "$TARGET" \
|| die "[1b/5] setfacl -b failed on target root"
# ===== 2) 「新規作成物」向けの default ACL をあなたの想定どおりに設定 =======
# - あなたが普段実行している3行(d:u / d:g / m::rwx)
# ※ m::rwx は“マスク(上限)”を広げるために重要
echo "[2/5] Set default ACLs recursively (your standard 3 lines)"
sudo setfacl -Rm d:u:"$USER_NAME":rwx "$TARGET" \
|| die "[2/5] setfacl d:u failed"
sudo setfacl -Rm d:g:"$GROUP_NAME":rwx "$TARGET" \
|| die "[2/5] setfacl d:g failed"
sudo setfacl -Rm m::rwx "$TARGET" \
|| die "[2/5] setfacl m::rwx (mask) on tree failed"
# ===== 3) 「既存の全ファイル/全ディレクトリ」に“今すぐ効く”アクセスACLを適用 =====
# - デフォルトACLは既存には効かないので、ここでアクセスACLを再帰付与
# - さらに m::rwx(アクセスACLのmask)を明示して effective を必ず rwx にする
echo "[3/5] Grant EFFECTIVE rwx to ALL existing files/dirs (access ACL + mask)"
sudo setfacl -R -m u:"$USER_NAME":rwx,g:"$GROUP_NAME":rwx,m::rwx "$TARGET" \
|| die "[3/5] setfacl access ACL (u/g/m rwx) on tree failed"
# ===== 4) 既存の全ディレクトリに default の mask=rwx を念押しで明示 ===========
# - 新規作成物の mask も必ず rwx になるよう保証(テンプレの上限を固定)
echo "[4/5] Ensure default mask=rwx on ALL directories (for future items)"
sudo find "$TARGET" -type d -exec setfacl -m d:m::rwx {} + \
|| die "[4/5] setfacl d:m::rwx on dirs failed"
# ===== 5) 完了表示 ============================================================
printf '%s%sOK:%s ACL applied (existing + future) under: %s user=%s group=%s\n' \
"$BOLD" "$RED" "$NC" "$TARGET" "$USER_NAME" "$GROUP_NAME"
以上です。
大枠の考え方は、
https://zenn.dev/tazzae999jp/articles/07bed12c3ae6c0#posix-acl
でよいです。
実行時の成功イメージ
下記のようになればOK
$ ~/aclfull.sh /example/path/localGitDir
Target: /example/path/localGitDir
User : myuser
Group : mygroup
[1/5] Clear ONLY default ACLs under target (avoid stale defaults)
[1b/5] Clear all ACL on the top directory (reset root ACL of target)
[2/5] Set default ACLs recursively (your standard 3 lines)
[3/5] Grant EFFECTIVE rwx to ALL existing files/dirs (access ACL + mask)
[4/5] Ensure default mask=rwx on ALL directories (for future items)
OK: ACL applied (existing + future) under: /example/path/localGitDir user=myuser group=mygroup
軽く確認
本当は、末端まで再帰的にデフォルトのACLなどを確認なんでしょうけど
とりあえず、下記で、軽く確認しておけばよいでしょう。
getfacl /example/path/localGitDir
で、下記のようになればよい
getfacl: Removing leading '/' from absolute path names
# file: udemy/rails_order_form
# owner: myuser
# group: mygroup
user::rwx
user:myuser:rwx
group::r-x
group:mygroup:rwx
mask::rwx
other::r-x
default:user::rwx
default:user:myuser:rwx
default:group::r-x
default:group:mygroup:rwx
default:mask::rwx
default:other::r-x
Discussion